为什么箭头函数的 'this' 在嵌套对象字面量中没有变化?

why doesn't 'this' of an arrow function change inside an nested object literal?

我发现在嵌套对象文字中使用箭头函数时,'this' 关键字似乎总是指向 global

根据其他问题,以下代码片段可以解释为箭头函数的 'this' 是在词法上下文中定义的。

var c = 100;
var a = {c:5 , fn: () => {return this.c;} };
console.log(a.c); //100

但是,我无法理解以下代码(嵌套对象文字):

var c = 100;

var a = {
    c: 5,
    b: {
        c: 10,
        fn: ()=> {return this.c;}
    }
}

console.log(a.b.fn());// still 100, why not 5?

我的意思是,如果从语境方面考虑,a.b.fn中的'this'不应该指向a吗?

为什么,无论对象嵌套了多少层,所有 'this' 个实例都指向 window 还是全局?

它与this对象初始化器所在的位置相同。因此,在您的两个示例中,它与您的 var a = ... 行所在的 this 相同。 this 在给定的执行上下文中永远不会改变,并且对象初始化器不会创建新的执行上下文;只有函数和 eval 可以做到这一点。在您的示例中,唯一一次创建新的执行上下文是在您调用 fn 时,并且由于 fn 是一个箭头函数,它会关闭执行上下文中的 this已创建(恰好是您示例中的全局执行上下文)。

您在示例代码中看到 this.c100 的原因是 this 在全局范围内(在松散模式下)指的是全局对象,而 var 全局范围内的变量成为全局对象的属性,因此 this.cc 全局变量。

如果您将所有这些代码放在一个作用域函数中,如下所示:

(function() { // Or `(() => {`, doesn't matter in this case
    var c = 100;

    var a = {
        c: 5,
        b: {
            c: 10,
            fn: ()=> {return this.c;}
        }
    }
    console.log(a.b.fn());// still 100, why not 5?
})();    

...this.c 将是 undefined,因为尽管 this 仍将引用全局对象,但 c 将不再是全局变量(并且因此 属性 的全局对象)。

如果你想让 fn 中的 this 引用表达式 a.b.fn() 中的 b,那么你不需要箭头函数,你需要一个正常功能;你会得到 10a.b.c 的值),而不是 5a.c 的值)。

当然,由于这是一次性对象,fna 关闭,您也可以将 fn 的主体设为 return a.c;return a.b.c; 取决于你想要哪个 c

另一种思考方式是,文字中没有新的 "this" 作用域的概念。

另一方面,函数会引入新的作用域。

JavaScript 中唯一改变作用域的表达式是一个函数,从 ES6 开始,它是块(请注意,对象文字 不是 块,尽管有它周围的花括号)。这意味着:不在函数内部的所有内容都在全局范围内。

在全局范围内,this 指的是全局对象(window 在浏览器中)。唯一改变作用域的是箭头函数(是的,它们确实改变了作用域!)——但它在词法上绑定了 this(这意味着,它使用外部作用域中的 this),所以它仍然是全局对象。

如果您希望 this 引用 a 对象,请使用 IIFE 而不是对象字面量:

var c = 100;

var a = new function () {
    this.c = 5;
    this.b = {
        c: 10,
        fn: ()=> {return this.c;}
    }
}()

alert(a.b.fn()) // 5;

或者,将 b 绑定到 this:

var c = 100;

var a = {
    c : 5,
    b : new function () {
        this.c = 10;
        this.fn = ()=> {return this.c;}
    }()
}

alert(a.b.fn()) // 10;

或者,要将 this 绑定到 b,您还可以使用常规函数代替箭头函数:

var c = 100;

var a = {
    c: 5,
    b: {
        c: 10,
        fn: function () {return this.c;}
    }
}

alert(a.b.fn()) // 10;