Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Please explain bizarre behavior of .call(false)

> (function () { return this; }).call(false)
false

> !!(function () { return this; }).call(false)
true

In both Firefox 4 beta and Chrome latest.

It's like... when is a boolean, not a boolean?

like image 349
Domenic Avatar asked Feb 02 '11 19:02

Domenic


2 Answers

It appears that when a primitive boolean is passed as the first argument to call or apply, it is auto-boxed into a Boolean object. This is clear in Firebug on Firefox 4:

>>> (function () { return this; }).call(false)
Boolean {}

In Chrome's inspector, it's initially confusing but a little probing reveals the truth:

>>> (function () { return this; }).call(false)
false
>>> typeof (function () { return this; }).call(false)
"object"

All JavaScript objects are "truthy", even new Boolean(false) and new Number(0). Therefore, using two negation operators (the !! trick) casts them to a true boolean.

like image 190
ide Avatar answered Sep 19 '22 12:09

ide


I found this line in the specification that explains the behavior.

3. Else if Type(thisArg) is not Object, set the 
   ThisBinding to ToObject(thisArg). 

Essentially the false value will be converted to a boolean object. The first application of the ! operator will convert the object to true then invert to false. The second application of the ! operator will invert false to true.

Full Text

10.4.3  Entering Function Code 

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). 
4.  Else set the ThisBinding to thisArg. 
5.  Let localEnv be the result of calling NewDeclarativeEnvironment   
    passing the value of the [[Scope]] internal 
    property of F as the argument. 
6.  Set the LexicalEnvironment to  localEnv. 
7.  Set the VariableEnvironment to localEnv. 
8.  Let code be the value of F‘s [[Code]] internal property.  
9.  Perform Declaration Binding Instantiation using the function code  
    code and argumentsList as described in 
like image 29
ChaosPandion Avatar answered Sep 17 '22 12:09

ChaosPandion