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:

  1. function foo() {
  2. // return an arrow function
  3. return (a) => {
  4. // `this` here is lexically adopted from `foo()`
  5. console.log( this.a );
  6. };
  7. }
  8. var obj1 = {
  9. a: 2
  10. };
  11. var obj2 = {
  12. a: 3
  13. };
  14. var bar = foo.call( obj1 );
  15. 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:

  1. function foo() {
  2. setTimeout(() => {
  3. // `this` here is lexically adopted from `foo()`
  4. console.log( this.a );
  5. },100);
  6. }
  7. var obj = {
  8. a: 2
  9. };
  10. 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:

  1. function foo() {
  2. var self = this; // lexical capture of `this`
  3. setTimeout( function(){
  4. console.log( self.a );
  5. }, 100 );
  6. }
  7. var obj = {
  8. a: 2
  9. };
  10. 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:

  1. Use only lexical scope and forget the false pretense of this-style code.

  2. Embrace this-style mechanisms completely, including using bind(..) where necessary, and try to avoid self = 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.