真的被javascript es6 arrow函数的"封闭范围"搞糊涂了

use*_*895 6 javascript this ecmascript-6 arrow-functions

  • 我在网上做了很多研究,阅读了很多帖子,包括MDN等.
  • 我理解,对于传统的定义函数,函数中的"this"由调用/调用它们的对象(以及几种不同的情况,对象文字,新构造函数,事件处理程序等)定义.
  • 我理解对于箭头函数,"this"是通过封闭的上下文/范围而不是通过调用它们的对象来词法定义的(尽管我们可以使用传统定义的函数(比如说A)来包装箭头函数(比方说,B)和因此首先将对象引用传递给A,然后传递给B)

这里有问题:

  1. 究竟什么是封闭的背景?这是进一步复杂的,因为ES6允许{}成为块/范围/上下文.{}作为分隔符足以定义"封闭上下文",或者它必须在函数范围内.

  2. 一个具体的例子:

    let EventEmitter = require('events').EventEmitter; class Person extends EventEmitter { constructor(name) { super(); this.name = name; } } let mary = new Person('mary'); mary.on('speak', (said) => { console.log(${this.name}: ${said}); }); mary.emit('speak', 'you may delay, but time will not');

它只是设置自定义事件,并在触发自定义事件时添加回调函数.为什么这里的箭头功能不起作用?

"mary"是调用"on"函数的对象,该函数应将"on"中的"this"设置为"mary".最重要的是,箭头函数在其参数位置的"on"函数中定义(在词法上足够,对吧?),为什么箭头函数不能从其"封闭的上下文"中得到"this"值,也就是说,这里的"开"功能???

  1. 同样的例子,使用传统的函数定义:

    let EventEmitter = require('events').EventEmitter; class Person extends EventEmitter { constructor(name) { super(); this.name = name; } } let mary = new Person('mary'); mary.on('speak', function(s) { console.log(this); }); mary.emit('speak', 'you may delay, but time will not');

现在它有效.我理解,鉴于旧的函数定义方式,console.log(this)现在可以动态绑定到调用它的对象.但等等,"mary"是对象,"on"是被调用的直接函数.不应该"on"形成其中的匿名函数的闭包吗?而且我记得嵌套函数中的"this"无法访问其闭包的"this"(封闭的上下文,再次,呵呵),因此不应该得到"mary"引用.它为什么在这里工作?

  1. 当我们在函数中讨论某些事物(例如,A)时,它是否意味着A必须在函数的{}中,或者A也可以在参数/参数区域中?也就是说,function(){A}与function(A){}.

  2. 类似地,如果箭头函数作为函数(()=>()){}之类的参数传递,外部函数是否考虑其封闭范围?或者这种情况下的封闭范围是外部函数的外部?

以上可能听起来很愚蠢.非常感谢你的帮助.

And*_*ndy 5

我在这里可能没有准确地使用作用域这个词,但基本上只是将作用域视为变量名称到它们所引用的内存位置的映射;嵌套作用域的名称/变量对隐藏(覆盖)封闭(也称为父)作用域中具有相同名称的关联。

function foo() { // this is the "enclosing scope" of bar
  var a = 4    <-----------+
                           |
  var b = a // refers to --+

  function bar() {
    var a = 7    <-----------+
                             |
    var c = a // refers to --+
  }
}
Run Code Online (Sandbox Code Playgroud)

thisa其行为方式与上面的示例完全相同。

function作用域隐式定义了引用,this但 ES2015 箭头函数作用域和块作用域没有。如果这些定义是明确的,它们将如下所示:

function foo() { // this is the enclosing scope of baz and the block below
  var this = ...  <-----------+--+
                              |  |
  var b = this // refers to --+  |
                                 |
  {                              |
    var q = this // refers to ---+
  }

  function bar() { // this is the enclosing scope of baz
    var this = ...  <-----------+--+
                                |  |
    var c = this // refers to --+  |
                                   |
    var baz = () => {              |
      var d = this // refers to ---+
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在特定范围内引用的内存位置的实际this不是按词法定义的;它在运行时设置为调用函数的对象(的内存位置)。但是一个引用对另一个引用的遮蔽总是按词法定义的。


Pau*_*aul -1

传递给事件发射器回调的函数不会绑定到发射器的作用域,除非您这样做,无论它是传统函数还是粗箭头函数。

当他们说粗箭头函数绑定到词法作用域时,他们的意思是它不会创建自己的新作用域。

考虑:

function Bob(){
  this.a = 5;

  function getA() { return this.a;}

  this.getAReal = () => this.a 
}

const bob = new Bob();

bob.getA(); // undefined
bob.getAReal(); // 5
Run Code Online (Sandbox Code Playgroud)

  • *“胖箭头函数...不会创建自己的新作用域”* - 箭头函数确实有自己的作用域(它们可以有自己的局部参数和变量)。但它们不会绑定自己的“this”、“arguments”、“super”或“new.target”,而且“this”尤其最重要...... (4认同)