Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is boxing coercion in JavaScript?

Tags:

javascript

In You Don't Know JS - the Coercion Chapter I've read that with coercion, you never get result that is a complex value, like an object or an array. Boxing wasn't considered coercion in an accurate sense. How is boxing different from coercion in JavaScript behind the hood? I really can't see any difference on the surface.

like image 679
daremkd Avatar asked Dec 03 '15 13:12

daremkd


People also ask

What is JavaScript boxing?

Boxing is the process in which a primitive value is wrapped in an Object. When a primitive type is treated as an object, e.g., calling the toUpperCase() function, JavaScript would automatically wrap the primitive type into the corresponding object type. This new object type is then linked to the related built-in <.

What is Boxing and Unboxing in c#?

Boxing is the process of converting a value type to the type object or to any interface type implemented by this value type. When the common language runtime (CLR) boxes a value type, it wraps the value inside a System. Object instance and stores it on the managed heap. Unboxing extracts the value type from the object.


3 Answers

This is largely a matter of semantics.

First, let's define "boxing," since the term isn't commonly used in JavaScript (it doesn't appear in the spec, for instance):

"Boxing" is wrapping an object around a primitive value. For instance, new Number(42) creates a Number object for the primitive number 42.

The only automatic boxing done in JavaScript is:

  1. When you use a method on a primitive, like this:

    console.log("testing".toUpperCase());
    

    "testing" is a primitive string, and thus doesn't (and can't) have methods. When the JavaScript engine sees a property accessor operation with a primitive root, per spec it creates a wrapper object for that primitive (a String object for a primitive string, for instance) before retrieving the property. If the property is being called (e.g., "foo".toUpperCase()), in loose mode the wrapper object is this within the call (in strict mode it's the primitive string). Unless something within the method call retains the wrapper object, it's thrown away afterward.

  2. When you use a primitive as the first argument to Function#call or Function#apply in loose mode, it's boxed in order to be this during the call. (In strict mode, this can be a primitive.) Unless the function being called retains a reference to the wrapper object, it's thrown away when the call is done.

Unboxing is, of course, the converse: Getting the primitive from the boxing object.

The language in the specification calls boxing "conversion":

From §7.1.13:

The abstract operation ToObject converts argument to a value of type Object...

However, it calls unboxing both "conversion" and "coercion":

From §7.1.1:

The abstract operation ToPrimitive converts its input argument to a non-Object type

From §4.3.16:

A Boolean object can be coerced to a Boolean value.

From §4.3.19:

A String object can be coerced to a String value...

At the end of the day, what matters is that we understand what happens when. I suspect that a strong distinction between convert and coerce has not intentionally been made by the authors.

like image 98
T.J. Crowder Avatar answered Oct 13 '22 00:10

T.J. Crowder


Boxing and coercion are different things, that can happen independantly, one or the other, or both of them.

  • Boxing is wrapping a primitive inside an Object.
  • Coercion is like interpreting a primitive as a different type.

If you see that boxing is converting the type of the given value, then that is both, conversion* and boxing.

e.g.:

var sp = 'abc';              // string primitive

// boxing
var so = new String( sp );   // string object, created from string primitive

// first conversion* and then boxing
var sn = new String( 123 ); // string object, created from a number

// coercion without boxing
var n = '3' - 1;            // number 2

*) I do not know if the coercion at '3' - 1 is done by the same part of the javascript engine as the conversion at new String( 123 ), but I think it is valid to think this way.

You could use boxing to do things you can only do with objects, e.g.:

var s = new String('a');
s.id = 123
// --> String { 0: "a", id: 123, length: 1 }

I never needed to use boxing explicitly, only implicitly as in e.g. "abc".charAt(0).

(opinion:)

Anyway, in my understanding, the word coercion is used to highlight the fact that it happens implicitly (in a context with other types), as opposed to the words casting or conversion. That would mean there is never an explicit coercion! You can't really DO coercion. Coercion just happens.

But the rules of coercion can be utilized to force a type, e.g.: '' + 3 is actually a string concatenation, but because of implicit coercion it can be used for conversion. On the other hand, +'3' or Number('3') would be an explicit conversion, not a coercion. (The spec seems not to make a clear distinction here.)

So, to rephrase the above in an opinionated way:

  • Boxing is wrapping a primitive inside an Object.
  • Coercion is something that happens, not something you can do.
  • Conversion can be done explicitly, or by utilizing boxing or coercion
like image 32
kca Avatar answered Oct 13 '22 01:10

kca


T.J. Crowder gives the correct answer. Just to add, the term "boxing" is not typically used in the JavaScript world, and the spec doesn't use it, but it does exists. The wrapping of primitives as Objects is a form of boxing, and Kyle Simpson of YDKJS is very clear in his talks and books that boxing is a form of implicit coercion.

This misunderstanding is unfortunately part of the reason why the old (and incorrect) statement that "everything is an Object in JavaScript" is still frequently encountered. If people were taught that primitives are not objects, but they can be coerced to act as objects by the JS entine in the form of boxing, a lot of these misunderstandings would disappear.

like image 1
Ryan Avatar answered Oct 13 '22 01:10

Ryan