这里有问题:
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”值,也就是说,这里的“开”功能???
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”引用。它为什么在这里工作?
以上可能听起来很愚蠢。非常感谢你的帮助。
我可能在这里没有精确地使用“范围”一词,但基本上只是将范围视为变量名称的映射到它们所指的内存中的位置;嵌套作用域的名称/变量将封闭(又称父作用域)中具有相同名称的阴影(覆盖)关联配对。
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 lambda范围和块范围没有。如果它们是明确的,那么这些定义会是什么样子:
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
在特定范围内引用的内存位置的实际值不是词法定义的;它在运行时设置为调用函数的对象的(内存位置)。但是,另一个引用的阴影总是在词法上定义。
箭头函数的this
是最近的函数范围,意味着使用function
关键字定义的函数的范围。
即使箭头函数以某种方式嵌套,这也适用,如
function scope() {
const arrow = a => b => this.foo(a, b);
}
这里的this
是this
的scope
。
“mary”是调用“on”函数的对象,该函数应将“on”中的“this”设置为“mary”。最重要的是,箭头函数在其参数位置的“on”函数中定义(在词法上足够,对吧?),为什么箭头函数不能从其“封闭的上下文”中得到“this”值,也就是说,这里的“开”功能???
是的,this
内的on
是mary
。然而,这并不意味着on
的实现将其mary
的回调称为this
,或任何其他特定的this
- 由on
的实现定义。此外,管理其“this”的箭头函数的“上下文”不是on
,也不是整个mary.on
语句,也不是一些封闭的{}
块,而是其中发生的函数范围。
我很难解密这个概念,但最近却把头脑包裹起来。
所以要理解这一点,我们应该首先了解什么是范围?范围是引擎在查找变量时所遵循的一组规则。所以在实践中,从You don't know JS这本书中可以很好地描述它作为引擎和范围之间的对话。如果你考虑一个简单的左手任务,如let a = 1;
,谈话将是这样的:
现在想象一下这样的场景:console.log(a)
在JavaScript中,有不同的方法来定义范围。但是为了简单回答这个问题,我们来谈谈功能范围。 (您也可以阻止定义范围)
// global scope
function foo(a) {
//foo scope
var b = a * 2;
function bar(c) {
// bar scope
console.log( a, b, c );
}
bar(b * 3);
}
foo( 2 ); // 2 4 12
从上面的例子中我可以很容易地发现2个范围,foo
范围和bar
范围。
你可以看到在foo中调用bar并且它打印了3个值,a
和b
,它们在foo
和c
的范围内,这是bar
的范围。它可以这样做,因为范围查找不会仅在当前范围内发生,它会继续检查它的父范围(封闭范围),直到它到达全局范围。
所以在层次结构中我们会看到类似的东西
在这种情况下,foo
范围是bar
的封闭范围,因为它实际上包含了内部的条形。
除非你这样做,否则传递给事件发射器回调的函数不会绑定到发射器的作用域,无论它是传统函数还是胖箭头函数。
当他们说胖箭头函数绑定到词法范围时,他们意味着它不会创建自己的新范围。
考虑:
function Bob(){
this.a = 5;
function getA() { return this.a;}
this.getAReal = () => this.a
}
const bob = new Bob();
bob.getA(); // undefined
bob.getAReal(); // 5