While working on another problem, I created this fiddle:
http://jsfiddle.net/tr2by/
function foo() {
// console.log(_.isBoolean(this));
conso
First of all I assume you are talking about automatic conversion of primitive values to objects. This happens in two cases in JavaScript:
this
value to .call
or .apply
(not in strict mode though)."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 providedthisArg
, and a caller providedargumentsList
:
- If the function code is strict code, set the
ThisBinding
tothisArg
.- Else if
thisArg
isnull
orundefined
, set theThisBinding
to the global object.- Else if
Type(thisArg)
is notObject
, set theThisBinding
toToObject(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:
- Let
baseReference
be the result of evaluatingMemberExpression
.- Let
baseValue
beGetValue(baseReference)
.
[...]8. Return a value of type
Reference
whosebase
value isbaseValue
and whose referenced name ispropertyNameString
, and whosestrict
mode flag isstrict
.
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 byGetValue
whenV
is a property reference with a primitive base value. It is called usingbase
as itsthis
value and with propertyP
as its argument. The following steps are taken:
- Let
O
beToObject(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:
- Let
lref
be the result of evaluatingLeftHandSideExpression
.- Let
rref
be the result of evaluatingAssignmentExpression
.- Let
rval
beGetValue(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.
The other answers provide detailed information about when autoboxing occurs, but here's a couple more things to remember:
Autoboxing does not occur when using the in
operator, which throws a TypeError
if the value received is not an object. A simple solution is to manually box the object with Object(value)
.
Some form of autoboxing occurs when iterating using for...of
or the spread syntax [...value]
which allows strings to be iterated.
Javascript boxes the this
argument provided to call
and apply
in non-strict mode. From MDN:
if the method is a function in non-strict mode code,
null
andundefined
will be replaced with the global object, and primitive values will be boxed.