enclosing context/scope
, not by objects invoking them (though we can use a traditionally defined function (say, A) to wrap arrow functions (say, B) and thus pass the object reference to A first, and then to B)Here come the questions:
what exactly is an enclosing context
? This is further convoluted since ES6 allows {}
to be a block/scope/context. Are {}
as delimiters good enough to define an "enclosing context" or it has to be within a function scope.
One specific example:
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');
It simply setups a custom event and adds a callback function when the custom event is triggered. Why the arrow function here doesn't work?
"mary" is the object that calls the "on" function, which should set "this" within "on" to be "mary". The most important thing is, the arrow function is defined in "on" function in its parameter position (lexically enough, right?), why the arrow function can't get "this" value from its "enclosing context", that is, the "on" function here???
the same example, with conventional function definition:
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');
Now it works. I understand that given the old way of function definition, console.log(this) can now be dynamically bound to the object calling it. But wait, "mary" is the object and "on" is the immediate function being called. Shouldn't "on" form a closure for the anonymous function within it? And I remember "this" within the nested function cannot access "this" of its closure (the enclosing context, again, huh) and thus should not get the "mary" refernce. Why it works here?
When we talk about something (say, A) within a function, does it mean A have to be in the {}
of the function, or A could be in the parameter/argument area as well? That is, function(){A}
vs. function(A){}
.
similarly, if an arrow function is passed as a parameter like function(()=>()) {}
, does the outer function considered its enclosing scope? Or the enclosing scope in this case would be the outer of outer function?
The above might sound very stupid. Thanks a lot for your help.
Since arrow functions don't have their own arguments , you cannot simply replace them with an arrow function. However, ES2015 introduces an alternative to using arguments : the rest parameter. // old function sum() { let args = []. slice.
Closures and nested scope However when a function is defined within another function the inner function has access to the variable scope of the outer function. This nesting of functions also results in a nesting of scope. The outer scope is said to “enclose” (hence the term closure) the scope of the inner function.
An arrow function doesn't have its own this value and the arguments object. Therefore, you should not use it as an event handler, a method of an object literal, a prototype method, or when you have a function that uses the arguments object.
Since regular functions are constructible, they can be called using the new keyword. However, the arrow functions are only callable and not constructible, i.e arrow functions can never be used as constructor functions. Hence, they can never be invoked with the new keyword.
I'm probably not using the word scope precisely here, but basically just think of a scope as a map of variable names to what locations in memory they refer to; a nested scope's name/variable pairs shadow (override) associations with the same name in the enclosing (aka parent) scope.
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
behaves exactly the same way as a
does in the above example.
function
scopes implicitly define a reference for this
but ES2015 arrow function scopes and block scopes do not. Here is what those definitions would look like if they were explicit:
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 ---+
}
}
}
The actual value at the memory location that this
refers to in a particular scope is not lexically defined; it is set at runtime to the (memory location of the) object a function is called upon. But the shadowing of one reference by another is always defined lexically.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With