前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >The this parameter in arrow function - Arrow function中的this参数

The this parameter in arrow function - Arrow function中的this参数

作者头像
lesM10
发布2019-08-26 17:01:37
9050
发布2019-08-26 17:01:37
举报
文章被收录于专栏:自译文章/自学记录

当我在阅读Secrets of the JavaScript Ninja一书时,在该书的第四章末尾的Exercises中有这样两个问题。

代码语言:javascript
复制
When running the following code, which of the assertions will pass?
function Ninja(){
  this.whoAmI = () => this;
}
var ninja1 = new Ninja();
var ninja2 = {
  whoAmI: ninja1.whoAmI
};
assert(ninja1.whoAmI() === ninja1, "ninja1 here?");
assert(ninja2.whoAmI() === ninja2, "ninja2 here?");
代码语言:javascript
复制
Which of the following assertions will pass?
function Ninja(){
  this.whoAmI = function(){
    return this;
  }.bind(this);
}
var ninja1 = new Ninja();
var ninja2 = {
  whoAmI: ninja1.whoAmI
};
assert(ninja1.whoAmI() === ninja1, "ninja1 here?");
assert(ninja2.whoAmI() === ninja2, "ninja2 here?");

起初,我的猜想是:

  • 第一个问题的答案是:ninja1.whoAmI() === ninja1,ninja1.whoAmI() === window
  • 第二个问题的答案是:ninja1.whoAmI() === ninja1,ninja2.whoAmI() === ninja1

对于第一个问题的回答,我不确定。因为书中对于arrow functionthis的解释,我也不是很理解。原文是这样的:arrow functions don’t get their own implicit this parameter when we call them; instead they remember the value of the this parameter at the time they were created. 当我们调用arrow functions时,它们没有自己的隐式的this参数;它们只记得 在创建它们时 this参数的值

对于第二个问题的回答,我的根据是书中的这样一段话:

代码语言:javascript
复制
The bind method is available to all functions, and is designed to 
create and return a new function that’s bound to the passed-in 
object (in this case, the button object). The value of the this 
parameter is always set to that object, regardless of the way the 
bound function was invoked. Apart from that, the bound function 
behaves like the originating function, because it has the same code 
in its body.

所有的`function`都有`bind method`这个方法,该方法创建并返回
一个`新的function`,这个`新的function`被绑定到传入的对象上。
不管`新的function`是以何种方式被调用的,在该`新的function`中 
`this`的值永远都是传入的对象。
除此以外,`新的function`在行为上 和原来的函数类似,
因为`新的function`和原来的函数`function body`有着同样的代码。

所以我对上面的代码加了一些assert,并运行它。因为把问题1和问题2的测试都放在一起了,所以对问题2的代码做了些改动 以便测试。

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
  <title>Using arrow functions to work around callback function contexts</title>
  <meta charset="utf-8">
  <script src="../assert.js"></script>
  <link rel="stylesheet" type="text/css" href="../assert.css">
</head>
<body>
  <script>
    function Ninja(){
      this.whoAmI = () => this;
    }

    var ninja1 = new Ninja();
    var ninja2 = {
      whoAmI: ninja1.whoAmI
    };
    
    assert(ninja1.whoAmI() === ninja1, "ninja1.whoAmI() === ninja1");
    assert(ninja2.whoAmI() === ninja2, "ninja2.whoAmI() === ninja2");

    assert(ninja2.whoAmI() === window, "ninja2.whoAmI() === window");
    assert(ninja2.whoAmI() === ninja1, "ninja2.whoAmI() === ninja1");

    assert(ninja1.whoAmI === ninja2.whoAmI, "ninja1.whoAmI === ninja2.whoAmI");


    function Person(){
      this.whoAmI = function(){
        return this;
      }.bind(this);
    }

    var p1 = new Person();
    var p2 = {
      whoAmI: p1.whoAmI
    }

    assert(p1.whoAmI() === p1, "p1.whoAmI() === p1");
    assert(p2.whoAmI() === p2, "p2.whoAmI() === p2");

    assert(p2.whoAmI() === window, "p2.whoAmI() === window");
    assert(p2.whoAmI() === p1, "p2.whoAmI() === p1");

    assert(p1.whoAmI === p2.whoAmI, "p1.whoAmI === p2.whoAmI");

  </script>
  
</body>
</html>

运行结果如下图:

Screen Shot 2018-04-19 at 6.04.33 PM.png

  • 根据运行结果的第五行和第十行,可以看出ninja1.whoAmIninja2.whoAmI是同一个函数。
  • ninja2.whoAmI() === ninja1这个结果在问题2中不显得那么奇怪,因为书中的话 已经解释的相当清楚了。
  • 但是ninja2.whoAmI() === ninja1这个结果在问题1中是显得有点奇怪的,因为 它和我预期的ninja2.whoAmI() === window 不一样。

所以我就搜了下,Stack Overflow中有类似的 但不完全一样的问题,但是其中的一些回答也适用于我的问题。 Arrow functions bind their this when they are created do not have this, arguments or other special names bound at all - when the object is being created the name thisis found in the enclosing scope. Arrow functions没有this arguments这些参数。当Arrow functions被创建时,this参数是在enclosing scope中被找到的。

并且下面的两段代码近似相等

代码语言:javascript
复制
function Ninja(){
      this.whoAmI = () => this;
}

can be translated into a vague approximation of the arrow syntax in ES5:

代码语言:javascript
复制
function Ninja(){
  this.whoAmI = function(){
    return this;
  }.bind(this);
}

在问题1中的结果ninja2.whoAmI() === ninja1也就得到了解释。


所以说,书中的话并不是那么的准确:arrow functions don’t get their own implicit this parameter when we call them; instead they remember the value of the this parameter at the time they were created. 换个更准确的说法,就应该是:Arrow functions bind their this when they are created do not have this, arguments or other special names bound at all - when the object is being created the name thisis found in the enclosing scope. 尽管解决了一些我的疑问,但是 我还是不清楚: 即,函数是何时被创建的。

通过回顾之前的一篇文章,让我对函数是合适创建的有了一些新的认识: 编译时 对所有代码进行逐行检测 。检测到所有的var(var当然也包括函数的定义,但是不包括赋值表达式右侧的函数定义),并分配存储空间。 注意是先编译后执行,编译时为所有的变量的定义 分配好存储空间(函数的定义也视作var声明,因此函数的定义 也被分配了存储空间),要区分compilation phase和execution phase。并且编译也不是一次性完成的,每当遇到要执行的函数时,会对要执行的函数进行编译(大概 函数就是在此时被创建的吧?)。因此编译和执行时交叉进行的。

转载请注明出处

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.04.19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档