箭头功能 - 为什么将全局对象打印到控制台?

Arrow functions - why does this print the global object to the console?

为什么 o.foo() 将全局对象打印到控制台?

let o = {
  foo: () => console.log(this),
  bar() { console.log(this); }
};

o.foo(); // Global object / undefined
o.bar(); // o

我认为箭头函数的等价物可能是这样的(但不是):

let o = {
    foo: function() {
        console.log(this);
    },
    bar() {   
        console.log(this);
    }
};

o.foo(); // o
o.bar(); // o

箭头函数保留 周围execution contextthis 从它们被声明时起。它们不会像正常方法那样一直更改 this

在您的示例中,foo 周围没有执行上下文,因此 thisundefined。这与在相同范围内使用 function 关键字声明并以相同方式调用的函数具有相同的行为。您可以使用以下方法进行测试:

let foo = () => { return this; }
console.log(foo() === undefined);

来自 the spec at 14.2.16:

Any reference to arguments, super, or this within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.

(强调我的)

有趣的是,当箭头函数出现在全局范围内时,the BabelJS transpiler 只是输出

"use strict";

var foo = function foo() {
  return undefined;
};

好像那是唯一正确的行为。阅读规范,它似乎并不那么严格,但这似乎是正确的做法。

如果您设法运行 ES6 代码使用不带模块的箭头,那么您似乎可以像这样结束全局对象。每 the spec at 10.2.1:

  • Global code is strict mode code if it begins with a Directive Prologue that contains a Use Strict Directive (see 14.1.1).
  • Module code is always strict mode code.

因此有可能在非严格上下文中获取 ES6 代码。如果发生这种情况,那么 this 将使用经典回退并设置为 window(在 the spec at 9.2 中作为未定义的 [[ThisMode]])。

在这个例子中,没有立即封闭的函数,因此没有词法范围可供选择,所以 this 最终未定义。

在您的第二个示例中,this 上的捕获没有任何区别:

let o = {
    foo: function() {
        var self = this;
        console.log(self);
    },
    bar() {
        
        console.log(this);
    }
};

var self 语句在函数内,所以它不会做任何事情。如果你要这样做:

let o = {
    foo: function() {
        var self = this;
        return function() {
            console.log(self);
        }
    }(),
    bar() {
        
        console.log(this);
    }
};

那么它将具有您期望的行为(大致),尽管 this 仍然是未定义的(或全局对象),因为您不在要捕获的词法环境中。

如果你要使用

class Foo {
  bar() {
    let baz = () => { return this; }
  }
}

然后 bar 可以转译为

function bar() {
  var _this = this;

  var baz = function baz() {
    return _this;
  };
}

它可以满足您的需求。这之所以有效,是因为要捕获周围的上下文。