Lexical this
Normal functions abide by the 4 rules we just covered. But ES6 introduces a special kind of function that does not use these rules: arrow-function.
Arrow-functions are signified not by the function
keyword, but by the =>
so called “fat arrow” operator. Instead of using the four standard this
rules, arrow-functions adopt the this
binding from the enclosing (function or global) scope.
Let’s illustrate arrow-function lexical scope:
function foo() {
// return an arrow function
return (a) => {
// `this` here is lexically adopted from `foo()`
console.log( this.a );
};
}
var obj1 = {
a: 2
};
var obj2 = {
a: 3
};
var bar = foo.call( obj1 );
bar.call( obj2 ); // 2, not 3!
The arrow-function created in foo()
lexically captures whatever foo()
s this
is at its call-time. Since foo()
was this
-bound to obj1
, bar
(a reference to the returned arrow-function) will also be this
-bound to obj1
. The lexical binding of an arrow-function cannot be overridden (even with new
!).
The most common use-case will likely be in the use of callbacks, such as event handlers or timers:
function foo() {
setTimeout(() => {
// `this` here is lexically adopted from `foo()`
console.log( this.a );
},100);
}
var obj = {
a: 2
};
foo.call( obj ); // 2
While arrow-functions provide an alternative to using bind(..)
on a function to ensure its this
, which can seem attractive, it’s important to note that they essentially are disabling the traditional this
mechanism in favor of more widely-understood lexical scoping. Pre-ES6, we already have a fairly common pattern for doing so, which is basically almost indistinguishable from the spirit of ES6 arrow-functions:
function foo() {
var self = this; // lexical capture of `this`
setTimeout( function(){
console.log( self.a );
}, 100 );
}
var obj = {
a: 2
};
foo.call( obj ); // 2
While self = this
and arrow-functions both seem like good “solutions” to not wanting to use bind(..)
, they are essentially fleeing from this
instead of understanding and embracing it.
If you find yourself writing this
-style code, but most or all the time, you defeat the this
mechanism with lexical self = this
or arrow-function “tricks”, perhaps you should either:
Use only lexical scope and forget the false pretense of
this
-style code.Embrace
this
-style mechanisms completely, including usingbind(..)
where necessary, and try to avoidself = this
and arrow-function “lexical this” tricks.
A program can effectively use both styles of code (lexical and this
), but inside of the same function, and indeed for the same sorts of look-ups, mixing the two mechanisms is usually asking for harder-to-maintain code, and probably working too hard to be clever.