javascript - 真的被javascript es6箭头函数的 "enclosing scope"搞糊涂了

标签 javascript ecmascript-6 this language-design arrow-functions

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

问题来了:

  1. 封闭上下文到底是什么?这更加复杂,因为 ES6 允许 {} 成为 block /范围/上下文。 {} 作为分隔符是否足以定义“封闭上下文”,或者它必须在函数范围内。

  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”值,即,这里的“on”功能???

  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) 现在可以动态绑定(bind)到调用它的对象。但是等等,“mary”是对象,“on”是被调用的直接函数。 “on”不应该为其中的匿名函数形成一个闭包吗?我记得嵌套函数中的“this”无法访问其闭包的“this”(又是封闭上下文,呵呵),因此不应该获得“mary”引用。为什么它在这里起作用?

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

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

以上内容可能听起来很愚蠢。非常感谢您的帮助。

最佳答案

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

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 --+
  }
}

this 的行为方式与上述示例中的 a 完全相同。

function 作用域隐式定义了对 this 的引用,但 ES2015 箭头函数作用域和 block 作用域没有。如果这些定义是明确的,那么这些定义会是这样的:

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 ---+
    }
  }
}

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

关于javascript - 真的被javascript es6箭头函数的 "enclosing scope"搞糊涂了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42847683/

相关文章:

javascript - 从另一个文件导出所有常量

javascript - 从 JavaScript 渲染 HTML

javascript - 从 TabNavigator 内部 View 与 StackNavigator 的导航选项交互

javascript - 如何在我的 React 应用程序中使用样式化组件?

node.js - 在没有转译器的情况下使用 ES6 'import' 语句

java - 'this' :method not applicable for the argument, 的一些问题也改进了格式

javascript - 获取 JSON 中的最后一个元素不起作用

javascript - 如何使用 moment js 解析这个日期字符串

javascript - 顶级函数中的 "this"

javascript - 经典 ASP Javascript 引用中的 'this.value' 是什么意思?