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

Ben*_*Ben 4 javascript ecmascript-6

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

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

o.foo(); // Global object / undefined
o.bar(); // o
Run Code Online (Sandbox Code Playgroud)

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

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

o.foo(); // o
o.bar(); // o
Run Code Online (Sandbox Code Playgroud)

ssu*_*ube 6

箭功能保留this了的周围执行上下文从他们被宣布时.它们并不this像常规方法那样一直在变化.

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

let foo = () => { return this; }
console.log(foo() === undefined);
Run Code Online (Sandbox Code Playgroud)

根据14.2.16的规格:

在ArrowFunction中对arguments,super或this的任何引用都必须解析为词法封闭环境中的绑定.通常,这将是直接封闭函数的函数环境.

(强调我的)

有趣的是,当该箭头函数出现在全局范围内时,BabelJS转换器只是输出

"use strict";

var foo = function foo() {
  return undefined;
};
Run Code Online (Sandbox Code Playgroud)

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

如果您设法使用没有模块的箭头运行ES6代码,那么您最终可以使用全局对象.根据10.2.1的规格:

  • 全局代码是严格模式代码,如果它以包含使用严格指令的指令序言开头(见14.1.1).
  • 模块代码始终是严格的模式代码.

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

在这个例子中,没有立即封闭的函数,因此没有词汇范围可以拾取,因此this最终未定义.

在第二个示例中,捕获this并没有什么区别:

let o = {
    foo: function() {
        var self = this;
        console.log(self);
    },
    bar() {?        
        console.log(this);
    }
};
Run Code Online (Sandbox Code Playgroud)

var self语句在函数内,因此它不会执行任何操作.如果你这样做:

let o = {
    foo: function() {
        var self = this;
        return function() {
            console.log(self);
        }
    }(),
    bar() {?        
        console.log(this);
    }
};
Run Code Online (Sandbox Code Playgroud)

然后它会有你期望的行为(粗略地),虽然this仍然是未定义的(或全局对象),因为你不在被捕获的词汇环境中.

如果你要使用

class Foo {
  bar() {
    let baz = () => { return this; }
  }
}
Run Code Online (Sandbox Code Playgroud)

那么bar可以归结为

function bar() {
  var _this = this;

  var baz = function baz() {
    return _this;
  };
}
Run Code Online (Sandbox Code Playgroud)

哪能做到你想要的.这只能起作用,因为有一个周围的上下文要捕获.