首先,看一段代码:函数
var obj = { foo: function() { if( this === obj ) { console.log('this is the obj !'); } else { console.log('this is not the obj !'); } } }
用不一样的方式调用obj的foo方法有不一样的结果:this
obj.foo(); // this is obj ! (obj.foo)(); // this is obj ! (0 || obj.foo)(); // this is not obj !
第一种状况,obj.foo(); 无需解释。对象
最后一种状况也很好解释,(0 || obj.foo)(); 的第一个括号内是一个逻辑运算表达式,按照 || 运算符的处理逻辑,该表达式返回的是 obj.foo 的求值结果。而 obj.foo 的求值结果是一个纯粹的函数值,于是在函数值被调用的执行环境中,this 确定不是原来的 obj 。ip
但第二种状况比较费解!
按直觉,(obj.foo) 应该会返回一个纯粹的函数值,所以在该函数值被调用的执行环境中,this 应该不是原来的 obj 。但实际状况并不是如此!io
为何会这样?console
这得从 JavaScript 的成员表达式以及括号()在表达式中的做用提及。function
首先,必定要明白 obj.foo 是一个成员表达式,其值包含对象 obj 和属性 foo 两部分。成员表达式的值同时也是一个左值,即,其能够用在赋值表达式的左侧,是能够被赋值的。变量
当左值参与表达式运算时,会触发左值求值操做,从而将其转换成通常值(俗称,右值)以后才参与运算。这就是为何 (0 || obj.foo) 中的 || 运算符会触发将 obj.foo 求值为函数值的缘故。方法
但在 (obj.foo) 表达式中,括号内并无任何运算符,因此 obj.foo 依旧是成员表达式的值。co
那么,包裹表达式的括号 ( ) 会触发对其包裹的表达式进行求值操做吗?
答案是:包裹表达式的括号 ( ) 不会触发求值操做!
所以,( obj.foo ) 依旧返回了成员表达式的值,对其发起调用操做,就是基于对象 obj 和 属性 foo 发起调用,因此其调用执行环境中的 obj 就是 this !
关于 表达式中的括号 () 不触发求值,还能够用如下代码证实:
var x; (x) = 123; // 这是正确的写法,并能正确运行!
上面代码中,x 是一个变量,也是一个左值。若是 (x) 的括号触发了对 x 的求值,其结果必定是 undefined 值,而再也不是左值,就不能赋值,上面的代码就会出错。而以上代码运行彻底正确,所以能够证实:表达式的括号必定不会求值。
其实,表达式中的括号 () 除了在函数后面用做调用运算符以外,其余状况根本就不是一个运算符,仅仅用于提高运算关系的优先级!