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

Javascript 箭头功能-为什么要将全局对象打印到控制台?,javascript,ecmascript-6,Javascript,Ecmascript 6,为什么o.foo()会将全局对象打印到控制台 let o = { foo: () => console.log(this), bar() { console.log(this); } }; o.foo(); // Global object / undefined o.bar(); // o 我认为箭头函数的等价物可能是这样的(但事实并非如此): 箭头函数保留声明时周围环境的此。它们不会像普通方法一样,一直改变这个 在您的示例中,没有围绕foo的执行上下文,因此此是未定义的。这

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

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

o.foo(); // Global object / undefined
o.bar(); // o
我认为箭头函数的等价物可能是这样的(但事实并非如此):

箭头函数保留声明时周围环境的
。它们不会像普通方法一样,一直改变
这个

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

let foo = () => { return this; }
console.log(foo() === undefined);
发件人:

ArrowFunction中对参数、super或this的任何引用都必须解析为词汇封闭环境中的绑定。通常,这将是一个直接封闭函数的函数环境

(强调矿山)

有趣的是,当该箭头函数出现在全局范围中时,只需输出

"use strict";

var foo = function foo() {
  return undefined;
};
好像那是唯一正确的行为。阅读规范时,它似乎没有那么严格,但这似乎是正确的做法

如果您在没有模块的情况下使用箭头运行ES6代码,那么最终可能会得到这样的全局对象。Per:

  • 如果全局代码以包含Use strict指令的指令序言开头,则它是严格模式代码(参见14.1.1)
  • 模块代码始终是严格的模式代码
因此,在非严格上下文中获取ES6代码是可能的。如果发生这种情况,
将使用经典回退,并设置为
窗口
(作为未定义的
[[ThisMode]]


在本例中,没有直接封闭函数,因此没有词汇范围可供选择,因此
最终未定义

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

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);
    }
};
然后它将具有您期望的行为(大致上),尽管
仍将是未定义的(或全局对象),因为您不在要捕获的词汇环境中

如果你要用

class Foo {
  bar() {
    let baz = () => { return this; }
  }
}
然后,
可以传输到

function bar() {
  var _this = this;

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

这正是你想要的。这仅仅是因为需要捕获周围的上下文。

“在本例中,没有直接封闭的函数,因此没有词汇范围可供选择,因此这最终是未定义的。”……或者全局对象处于草率模式?我认为“函数范围”在规范中不是一个定义良好的术语。您的意思是
[[Environment]]
internal property?我无法在我的机器上重现第二个行为,但这可能是因为Babel只是简单地将
let foo=()=>{return this;}
直接传输到
var foo=function foo(){return undefined;}(不是开玩笑)。这使我认为这是一个足够好的定义行为,可以依赖。用正确的术语替换“函数范围”,并添加了关于第二个示例的一些信息。FWIW,bable将
转换为
未定义的
,因为它假定每个文件都是一个模块。模块总是严格的,它们的
值总是
未定义
如果在脚本的顶层声明了arrow函数,则此
将引用
窗口
。我假设您从。请注意最大的区别:我在arrow函数外部声明了
self
,您在arrow函数内部声明了它。这不是它的工作原理。等价物为
var self=this;设o={foo:console.log(self);}@FelixKling是的。谢谢你澄清这一点。这是我的误解(我写下问题后意识到)。
function bar() {
  var _this = this;

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