admin管理员组

文章数量:1313082

So here is the code snippet from this modern JavaScript tutorial:

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

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

group.showList();

The tutorial tries to explain this in an arrow function, and it says:

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.

We know this in an arrow function is determined lexically. So the scope chain should be:

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

In this case, the outer scope of arrow function should be forEach instead of showList. Thus this in an arrow function is exactly the same as in forEach, which should be undefined since there is no thisArg passed to forEach. But in fact, this is group, which means it is exactly the same as in showList. So, it seems forEach doesn't hold a scope in this case? I am confused.

So here is the code snippet from this modern JavaScript tutorial:

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

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

group.showList();

The tutorial tries to explain this in an arrow function, and it says:

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.

We know this in an arrow function is determined lexically. So the scope chain should be:

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

In this case, the outer scope of arrow function should be forEach instead of showList. Thus this in an arrow function is exactly the same as in forEach, which should be undefined since there is no thisArg passed to forEach. But in fact, this is group, which means it is exactly the same as in showList. So, it seems forEach doesn't hold a scope in this case? I am confused.

Share Improve this question edited Jan 2, 2020 at 13:12 Boann 50.1k16 gold badges124 silver badges152 bronze badges asked Jan 2, 2020 at 12:28 ChorChor 9911 gold badge8 silver badges20 bronze badges 9
  • because you assign or create those methods in the scope of showList and lambdas share scope in js, also those cb get invoked not called ^^ no scope binding - furthermore arrow functions ignore bindings – Estradiaz Commented Jan 2, 2020 at 12:34
  • The forEach() and the arrow function are one and the same scope. The scope of the forEach() is informed by the type of function (arrow vs. conventional) you pass to it. – Mitya Commented Jan 2, 2020 at 12:35
  • Why arrow function is not in forEach scope?It should be from the perspective of lexical,right?I mean it just the same as function( ){ ( )=>{ } }(here the function is forEach) – Chor Commented Jan 2, 2020 at 12:41
  • @Estradiaz arrow functions ignore bindings ,but its this will be the same as in its outer scope,which in this question is forEach – Chor Commented Jan 2, 2020 at 12:42
  • Hmm isnt it that those arrow functions are created in showList and then passed to forEach where it gets called like cb.call(undefined, ...args), but as those are arrow functions they keep there scope bindings to parent ctx, those are passed as callbacks not created in the scope of foreach – Estradiaz Commented Jan 2, 2020 at 13:10
 |  Show 4 more ments

4 Answers 4

Reset to default 3

So the scope chain should be:

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

I think you are confused what "scope" means. It's a variable scope, in code typically delimited with braces {…}, the region in which any identifier always refers to the same variable.

There is no "forEach scope". It's just a function call. Just like there is no scope for the parameter list of the alert(…) call. There are only three scopes in your example:

global --> showList --> anonymous arrow function

There is also the 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 (where identifiers are resolved dynamically depending on where a function was called).

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.

source 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.

The outside function in this case is showList as you would realise that forEach is not a wrapping function for arrow function here instead it is just a call to a function which takes a callback.

Instead showList is the wrapping function. Hence it inherits this from showList

Perhaps this example will help you understand better:

'use strict';

function hello(greet) {
  greet()
}

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


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

group.showList();

Lexical scope is determined by where a function is defined.

You are passing the arrow function to forEach, so its scope has nothing to do with forEach.

It is the same reason that in this example, the function logs "one" and not "two":

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

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

one();

Scope is only created when an object/function is created (in this case).

In the case of .forEach, you are merely calling a function that is already created by the engine, meaning you are not creating any scopes when calling .forEach.

Conversely, when you define:

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

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

It translates to:

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

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

You are creating a function named "showList", and therefore you are creating a scope.

Before the showList() function is created, you created the group object, thus creating another scope, which, in this case, is the parent scope of showList().

Therefore, inside the showList() function, its this value is the group object.

本文标签: