js:关于'这个' ES5和ES6之间的关键字使用

时间:2017-04-28 02:16:12

标签: ecmascript-6 this

我目前正在学习ES6标准,对于箭头功能部分,我发现了一个令人困惑的问题如下:

function foo() {
    setTimeout(() => {
        console.log('id:', this.id);
    }, 100);
}

var id = 21;

foo.call({ id: 42 });

以上是ES6标准,ES5如下

function foo() {
    setTimeout(function(){
        console.log('id:', this.id);
    }, 100);
}

var id = 21;

foo.call({ id: 42 });

In ES5, the output is id:21
In ES6, the output is id:42

我能理解ES6的结果。但与ES5的结果非常混淆。 foo()函数的调用站点是foo.call({id:42}),因此调用对象是{id:42},但是当它执行时,调用对象变为window。怎么样?

2 个答案:

答案 0 :(得分:1)

这里有几件。首先,要了解this本质上是一个由调用函数的东西自动设置的参数。这对理解至关重要。因此,在这种情况下,setTimeout负责调用您的函数,它基本上是fn.call(undefined),因此不会传入明确的this

接下来,您的示例:

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

VS

function foo() {
  setTimeout(function(){
    console.log('id:', this.id);
  }, 100);
}

箭头功能案例基本上是:

function foo() {
  var _this = this;

  setTimeout(function(){
    console.log('id:', _this.id);
  }, 100);
}

因此,在两种情况下比较this,第一种情况使用调用了this的{​​{1}},并且您的示例代码有效,因为您需要foo显式设置比。第二个示例使用foo.call({ id: 42 });传递的this,如上所述setTimeout

但是,从undefined 传入的this可能实际上不是最终在函数内公开的.call

  • 在非严格代码中:this直接传递,如果它是一个对象,但如果一个对象,this是全局对象(浏览器中的this,节点中的window
  • 在严格的代码中:global直接通过未更改的

由于您的示例代码未标记为this,这意味着您正在尝试此全局行为。这意味着你的两个例子基本上是这样的:

"use strict";

VS

function foo() {
  setTimeout(function(){
    console.log('id:', window.id); // reads "id" from the global object
  }, 100);
}

这里的最后一块是你的

function foo() {
  var _this = this;

  setTimeout(function(){
    console.log('id:', _this.id); // reads "this" from `foo.call(...)`
  }, 100);
}

属于全局范围,因此基本上是var id = 21; 。因此,这个价值贯穿始终。

我推荐的主要内容:

  • 不要在顶级范围内执行代码,这样您的window.id = 21声明就不会在var上结束。如果您使用CommonJS或Webpack的ES6模块语法等模块系统,则会自动执行此操作。如果您这样做,您的代码将按原样window记录,因为undefined不存在。
  • 始终使用window.id标记您的代码。这通常很容易。如果你正在使用CommonJS,只需将它放在文件的顶部,如果你正在使用ES6模块,它将被自动添加,因为ES6模块必须是严格的。如果您这样做,非箭头回调中的"use strict";将为this,因此undefined会引发错误。

答案 1 :(得分:0)

ES5:'this'被验证,直到函数实际调用(即function()或'new'关键字)。在你的情况下,setTimeout中的回调函数实际上是由window对象调用的(因此你的'this'原来是window对象),并且window对象在你声明之后有'a'属性。这就是它打印21的原因。

ES6:宣布你的功能后,'this'会被验证。因此'this'指向'call'函数中的任何内容。当然你可以尝试调用(窗口),然后你会看到21按预期打印出来,因为窗口有'a = 21'属性。

这是一个非常好的问题,我希望上面的解释有所帮助:)