为什么 (obj.foo)() 调用的执行环境中的 this 就是 obj ?

首先,看一段代码:

var obj = {
  foo: function() {
    if( this === obj ) {
      console.log('this is the obj !');
    }
    else {
       console.log('this is not the obj !');
    }
  }
}

用不同的方式调用obj的foo方法有不同的结果:

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 。

但第二种情况比较费解!

按直觉,(obj.foo) 应该会返回一个纯粹的函数值,因此在该函数值被调用的执行环境中,this 应该不是原来的 obj 。但实际情况并非如此!

为什么会这样?

这得从 JavaScript 的成员表达式以及括号()在表达式中的作用说起。

首先,一定要明白 obj.foo 是一个成员表达式,其值包含对象 obj 和属性 foo 两部分。成员表达式的值同时也是一个左值,即,其可以用在赋值表达式的左侧,是可以被赋值的。

当左值参与表达式运算时,会触发左值求值操作,从而将其转换成一般值(俗称,右值)之后才参与运算。这就是为什么 (0 || obj.foo) 中的 || 运算符会触发将 obj.foo 求值为函数值的缘故。

但在 (obj.foo) 表达式中,括号内并没有任何运算符,所以 obj.foo 依旧是成员表达式的值。

那么,包裹表达式的括号 ( ) 会触发对其包裹的表达式进行求值操作吗?

答案是:包裹表达式的括号 ( ) 不会触发求值操作!

因此,( obj.foo ) 依旧返回了成员表达式的值,对其发起调用操作,就是基于对象 obj 和 属性 foo 发起调用,所以其调用执行环境中的 obj 就是 this !

关于 表达式中的括号 () 不触发求值,还可以用以下代码证明:

var x;
(x) = 123;    // 这是正确的写法,并能正确运行!

上面代码中,x 是一个变量,也是一个左值。如果 (x) 的括号触发了对 x 的求值,其结果一定是 undefined 值,而不再是左值,就不能赋值,上面的代码就会出错。而以上代码运行完全正确,因此可以证明:表达式的括号一定不会求值。

其实,表达式中的括号 () 除了在函数后面用作调用运算符之外,其他情况根本就不是一个运算符,仅仅用于提升运算关系的优先级!

转载于:https://my.oschina.net/wangch5453/blog/732431

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值