Arrows and

I am browsing twitter and found this tweet:

https://twitter.com/_ericelliott/status/855598297939144704

Here's the code from the tweet:

const double = () => this.x * 2;
const numDouble = double.bind({ x: 5 });
numDouble();

      

When you run this snippet in the console, it will create NaN. How? The author explicitly binds the value of x, but still shows NaN.

The author also points out that the arrow function cannot link this. As I know the arrow function lexically binds the meaning of this shape surrounding the area. Then why is the author claiming this?

Please clarify my doubts and in advance for your help.

+3


source to share


2 answers


Arrow functions do not bindthis

. According to MDN:

Lack of binding this

As long as the arrow functions, each new function defines its own value this

(new object in the case of a constructor, undefined in strict mode function calls, a context object if the function is called as an "object method", etc.). This turned out to be annoying object-oriented programming style.

So this

your example will be a global object window

that doesn't appear to have a property called x

.



Example:

function foo() {
  let arrow = () => {
    console.log(this);     // will use foo this as arrow will never have its own this
  }
  
  arrow.call({"x": "x"});  // ... even if we specify it using bind, call, or apply
}

foo.call({"y": "y"});      // specifying the this for foo (this value will eventually be used by arrow because it will be availbale in its scope)
      

Run codeHide result


+5


source


The main thing to remember:

  • Arrow functions are closed over this

    , just like functions are closed over variables.
    (Actually, this is the same mechanism.) Regardless of this

    where the arrow function is created, what this

    happens when that arrow function is called. This will never happen again. Arrow functions ignore this

    they are called.

If you remember this, you will never be confused this

about the arrow function again.

When you run this snippet in the console, it will output NaN. How? The author explicitly binds the value of x, but it still shows NaN.

numDouble = double.bind({ x: 5 })

creates a new function ( numDouble

) that, when called, will call the original function ( double

) with the this

specified as the first argument bind

( { x: 5 }

). But since the arrow functions are to ignore this

they are called with, bind

it cannot control what this

they use.

The author also points out that the arrow function cannot relate this. As I know the arrow function lexically binds the value of this form surrounding the scope.

Yes, that means you cannot change it. Lexical binding is a way to close. This arrow function:

const a = () => {
    console.log(typeof this);
};

      

handles this

exactly the same way this traditional function handles thisWhereFunctionWasCreated

:



const thisWhereFunctionWasCreated = this;
const t = function() {
    console.log(typeof thisWhereFunctionWasCreated);
};

      

Just as you cannot change what a thisWhereFunctionWasCreated

variable is t

using when you call it, you cannot change what is this

used when you call it. (If thisWhereFunctionWasCreated

it is not const

, you can change the value it contains, but not that of the thisWhereFunctionWasCreated

variable thisWhereFunctionWasCreated

t

. But in this example, it is a constant because it is a this

constant.)

Since the arrow function completely ignores the this

caller, it doesn't matter what mechanism is used to try and tell the arrow function what to this

use, it won't work. obj.arrow()

whether you are this

implicitly calling the function as a method ( obj.arrow()

), either with call

or apply

( arrow.call(obj)

), or with bind

( const boundArrow = arrow.bind(obj); boundArrow();

), it will still use instead this

:

"use strict";

function Ctor() {
    
    // 'this' will be the object created by 'new Ctor'; grab it
    this.name = "outerThis";
    const outerThis = this;
    
    // 'traditional' doesn't close over 'this', so you CAN change
    // what 'this' it uses when you call it, in various ways
    function traditional(testNum) {
        console.log(testNum, "traditional:", getName(this));
    }
    
    // 'arrow' closes over 'this', so you CAN'T change
    // what 'this' it uses when you call it
    const arrow = testNum => {
        console.log(testNum, "arrow:      ", getName(this));
    };

    // Remember that the 'this' in a direct call is the global
    // object in loose mode, 'undefined' in strict mode; this
    // code is in strict mode
    console.log("Direct call (default 'this'):");
    traditional(1);              // 1 traditional: window
    arrow(1);                    // 1 arrow:       outerThis
    
    console.log("'obj.xyz()':");
    const obj = {
        name: "obj",
        arrow,
        traditional
    };
    obj.traditional(2);          // 2 traditional: obj
    obj.arrow(2);                // 2 arrow:       outerThis

    console.log("Using 'call':");
    traditional.call(obj, 3);    // 3 traditional: obj
    arrow.call(obj, 3);          // 3 arrow:       outerThis

    console.log("Using 'bind' and calling result:");
    const boundTraditional = traditional.bind(obj);
    const boundArrow = arrow.bind(obj);
    boundTraditional(4);         // 4 traditional: obj
    boundArrow(4);               // 4 arrow:       outerThis
}

function getName(t) {
    switch (t) {
        case undefined:
            return "undefined";
        case window:
            return "window";
        default:
            return t.name;
    }
}

new Ctor();
      

.as-console-wrapper {
    max-height: 100% !important;
}
      

Run codeHide result


The only thing that the bind

arrow function can do is bind arguments to it:

const arrow = (x, y) => x + y;
console.log(arrow(2, 3));      // 5

const arrowWith2 = arrow.bind(null, 2);
console.log(arrowWith2(3));    // 5

const arrowWith2And3 = arrow.bind(null, 2, 3);
console.log(arrowWith2And3()); // 5
      

Run codeHide result


(It also sets the name of the resulting function arrowWith2.name

"bound x"

[where x

is the name of the original function. So arrowWith2.name

in the above arrowWith2.name

, this is "bound arrow"

.)

0


source







All Articles