Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ES6 arrow function and lexical scope inside a function [duplicate]

let a = () => (
  {
    name:"Anna",
    func: () => console.log(this.name)
  }
)

let b = () => (
  {
    name:"Brian",
    func: function(){ console.log(this.name) }
  }
)

let c = function(){
  return(
    {
      name:"Charlie",
      func: function(){ console.log(this.name) }
    }
  )
}

let d = function(){
  return(
    {
      name:"Denny",
      func: () => console.log(this.name)
    }
  )
}

These 4 functions have mix & matched function syntax. When calling the nested function, the func: with arrow function returns blanks.

a().func() // returns blank
b().func() // returns "Brian"
c().func() // returns "Charlie"
d().func() // returns blank

I thought the arrow function retain the scope of "this"? The behavior seems to be the opposite of what I've thought. When did the arrow function went out of scope?

like image 349
Gundam Meister Avatar asked Jan 23 '18 22:01

Gundam Meister


Video Answer


2 Answers

When you define a and d, the value of this is the top-level window object, since you're not in the context of some other object, and this gets saved in the arrow functions. window.name is an empty string, so that's what you see when you call a.func() and d.func().

Arrow functions should generally not be used as method functions because they don't get access to the object they're called through. Use them when you want to preserve the binding of this from where you created them (just like other closure variables).

like image 79
Barmar Avatar answered Oct 10 '22 04:10

Barmar


For the A case, you literally are preserving this all the way back to window (if ran in a browser), so it would be window.name that you are returning.

As for D however, it was returning blank still because it was on the function level of "this" that was returning. In your case, since you aren't creating a new instance of D but using d as a functional object itself, this points also to window. (I'll post more about the later, but for now, here is an example).

let e = function(){
  this.name = "Elizabeth2"  //this is on the functional level
  return(
    {
      name:"Elizabeth1",
      func: () => console.log(this.name)
    }
  )
}
e().func();       // Elizabeth2 
                  // even though it is on the functional level, the way you're calling it here makes this.name == window.name;
let ee = new e(); // however, imagine if you did this kind of a call instead
ee.func();        // Elizabeth2
                  // this is also on the functional level, HOWEVER, it is not binding this.name to window.name
ee.name;          // Elizabeth1
e().name;         // Elizabeth1
e()['name'];      // Elizabeth1
e();              // {name: "Elizabeth1", func: ƒ}

now to show difference if func is bound to anonymous function rather than anonymous arrow function.

e = function(){
  this.name = "Elizabeth2"
  return(
    {
      name:"Elizabeth1",
      func: function(){console.log(this.name)}
    }
  )
}
e().func();  // Elizabeth1
e().name;    // Elizabeth1
e()['name']; // Elizabeth1
e();         // {name: "Elizabeth1", func: ƒ}
like image 26
simon Avatar answered Oct 10 '22 05:10

simon