为什么在这个代码片段中,箭头函数的外部作用域是在 showList 而不是 forEach 中?

Why in this code snippet is the outer scope of the arrow function in `showList` instead of `forEach`?

所以这是来自 modern JavaScript tutorial 的代码片段:

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(
      student => alert(this.title + ': ' + student)
    );
  }
};

group.showList();

本教程试图用箭头函数解释 this,它说:

Here in forEach, the arrow function is used, so this.title in it is exactly the same as in the outer method showList. That is: group.title.

我们知道箭头函数中的this是词法确定的。所以范围链应该是:

global--> showList-->forEach-->arrow function

在这种情况下,箭头函数的外部作用域应该是forEach而不是showList。因此,箭头函数中的 thisforEach 完全相同,后者应该是 undefined,因为没有 thisArg 传递给 forEach。但实际上,thisgroup,也就是说和showList完全一样。 那么,在这种情况下,forEach 似乎没有作用域?我很困惑。

The error occurs because forEach runs functions with this=undefined by default, so the attempt to access undefined.title is made.

That doesn’t affect arrow functions, because they just don’t have this.

来源https://javascript.info/arrow-functions

As we remember from the chapter Object methods, "this", arrow functions do not have this. If this is accessed, it is taken from the outside.

在这种情况下,外部函数是 showList,因为您会意识到 forEach 在这里不是箭头函数的包装函数,而只是对接受回调的函数的调用。

showList 是包装函数。因此它继承自 showList

也许这个例子可以帮助您更好地理解:

'use strict';

function hello(greet) {
  greet()
}

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],


  showList() {
    hello(() => console.log("Hello " + this.title))
  }
};

group.showList();

So the scope chain should be:

global--> showList-->forEach-->arrow function

我认为您对 "scope" 的含义感到困惑。它是一个变量范围,在代码中通常用大括号 {…} 分隔,该区域中任何标识符始终引用相同的变量。

没有“forEach范围”。这只是一个函数调用。就像 alert(…) 调用的参数列表没有作用域一样。您的示例中只有三个范围:

global --> showList --> anonymous arrow function

还有 call stack, outlining which function calls led to the execution of the current code. This does indeed contain forEach, which is calling the arrow function, which in turn will call the alert function. But this does not correspond to the scope in JavaScript (for which you will see more examples when learning about closures), which is why JavaScript is said to have lexical scope and not dynamic scope(根据调用函数的位置动态解析标识符)。

词法作用域由定义.

函数的位置决定

将箭头函数传递给forEach,所以它的作用域与forEach无关。

与此示例中的函数记录 "one" 而不是 "two" 的原因相同:

function one() {
    const value = "one";
    two( function() { console.log(value); } );
}

function two(argument) {
    const value = "two";
    argument();
}

one();

范围仅在创建 object/function 时创建(在本例中)。

.forEach 的情况下,您只是调用引擎已经创建的函数,这意味着您在调用 .forEach.

时不会创建任何范围

反之,当你定义:

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(
      student => alert(this.title + ': ' + student)
    );
  }
};

翻译成:

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList: function() {
    this.students.forEach(
      student => alert(this.title + ': ' + student)
    );
  }
};

您正在创建一个名为 "showList" 的函数,因此您正在创建一个作用域。

在创建 showList() 函数之前,您创建了 group 对象,从而创建了另一个作用域,在本例中,它是 showList() 的父作用域。

因此,在showList()函数内部,它的this值就是group对象。