Does JavaScript Autobox

Does javascript autobox?

First of all I assume you are talking about automatic conversion of primitive values to objects. This happens in two cases in JavaScript:

  1. When you pass a primitive value as the this value to .call or .apply (not in strict mode though).
  2. When you are trying to access a "property" of a primitive value, e.g. "foo bar".split().

In the first case the conversion is permanent, i.e. this will indeed reference an object, in the second the conversion only takes place internally for the duration of the evaluation

If you are not interested in the details of the conversion, you can ignore the rest of the answer.


1. Primitive value as this

When a function is exectued and its this value is not an object, it is converted to one, at least in non-strict mode. This is described in §10.4.3 Entering Function Code [spec] in the ECMAScript 5.1 documentation:

The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisArg, and a caller provided argumentsList:

  1. If the function code is strict code, set the ThisBinding to thisArg.
  2. Else if thisArg is null or undefined, set the ThisBinding to the global object.
  3. Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).

    [...]

As you can see in step three the value is converted to an object by calling ToObject [spec].

2. Property access

Something similar happens when you are trying to access properties (§11.2.1 Property Accessors [spec]). The quoted part here explains how the expression foo[bar] is evaluated, i.e. how property access with the bracket notation is evaluated. The part we are interested in applies to dot notation as well.

The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:

  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be GetValue(baseReference).

    [...]

   8. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

The important step is the last one: No matter to what MemberExpression evaluates, it is converted to a value of type Reference [spec]. This is a datatype only used in the specification and contains additional information about how the actual value should be retrieved from the reference (not to be confused with object references in actual JavaScript code!).

To get the "real" value/result from such a reference, the internal function GetValue(V) (§8.7.1) [spec] is called (just like in step 2 in the above algorithm), where it says:

The following [[Get]] internal method is used by GetValue when V is a property reference with a primitive base value. It is called using base as its this value and with property P as its argument. The following steps are taken:

  1. Let O be ToObject(base).

    [...]

Example:

Assume we have the expression

var foo = "BAR".toLowerCase();

This is an assignment expression which is evaluated as follows:

The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:

  1. Let lref be the result of evaluating LeftHandSideExpression.
  2. Let rref be the result of evaluating AssignmentExpression.
  3. Let rval be GetValue(rref).

    [...]

Step 1: The left hand side is evaluated, which is the identifier foo. How exactly identifiers are resolved is not important for this.

Step 2: The right hand side is evaluated, i.e. "BAR".toLowerCase(). The internal result of that evaluation will be a reference value, similar to:

REFERENCE = {
base: "BAR",
propertyNameString: "toLowerCase",
strict: false
}

and stored in rref.

Step 3: GetValue(rref) is called. The base of the reference is the value "BAR". Since this is a primitive value, ToObject will be called to convert it to a temporary String object. Furthermore, the reference is actually a property access, so GetValue will eventually call the method toLowerCase on the String object and return the method's result.

Can I define my string literal to autobox to another constructor? not String()

Caling new String(val) returns an instance object of String. It is not a primitive value, that's why it can be noticeably slower.

typeof new String('a random string') // object

In real life it is very rare case when you need to do such things. Usually String is called without new in order to simply convert value to string. In that case String('random string') will just return the same primitive value you passed in.

typeof String('a random string') // string

Try to add the third block to your tests:

for(var i = 0; i < 20000; i++) {
let a = String("a random string"); // no 'new'
a.split("");
}

And you will see that its performance is almost the same as for the simple initialisation like in your first block.

UPD:
According to tests, in some browsers the first block from the question still executes few times faster than one above. It probably happens because String(val) is a function call, what makes browser to do more actions than during simple initialisation.
Anyway, the main point of this answer is that creating object is slower than simple initialisation and it is quite unusual for String to be used like a constructor.

In JS, why am I able to use functions like toFixed() which resides in the prototype of the Number wrapper object on a primitive type?

This has to do with something with a concept called "Autoboxing", Javascript sees that you're trying to access a property on the primitive type and hence for a very brief moment at runtime, it converts the primitive value to its corresponding Wrapper object and proceeds with the property call, it then converts the value back to primitive type in most of the cases.

let a = 6.678; //primitive type

a= a.toFixed(1); // JS converts a to "Number Object" and then the function is called

console.log(a); // 6.7

Here's a very good answer to it Does javascript autobox?

Does Java autobox when assigning an int to an Object?

Will the above code first wrap the int literal 8 in an Integer and then assign its reference to variable ob?

Yes. (Or rather, it will box the int value into an Integer object, and then assign the reference to the variable ob. The fact that the integer value is a literal is irrelevant here, really. It could be a method call returning int, for example.)

Because the java language specification has nothing on this case.

That's not true. I mean, it doesn't explicitly deal with assigning to Object, but it works the same way as normal conversions.

Section 5.1.7 of the specification deals with boxing, which would convert int to Integer... and then assigning an Integer reference to an Object variable is a normal reference conversion.

Why autoboxing does not occur in this context?

you can read on Autoboxing here:

Autoboxing is the automatic conversion that the Java compiler makes
between the primitive types and their corresponding object wrapper
classes. For example, converting an int to an Integer, a double to a
Double, and so on. If the conversion goes the other way, this is
called unboxing.

and as you can read at the end, the types tat are auto boxed are: boolean, byte, char, float, int, long and short. array are not autoboxed

it might seems very logical for you that the compiler will do that, but that kind of behavior is very complicated and required a very sophisticated compiler.

How does instanceof operator actually work in JS?

JavaScript has a feature called autoboxing which converts primitives to Objects when you try to access properties on them.

instanceof doesn't autobox and a primitive number is not an instance of the Number class.

You can see, in the specification:


  1. If Type(O) is not Object, return false.


Related Topics



Leave a reply



Submit