7
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?

Zze
  • 15,599
  • 9
  • 68
  • 98
Gundam Meister
  • 825
  • 1
  • 13
  • 23
  • Does [this](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) help? – webnoob Jan 23 '18 at 22:15
  • read [documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) – Jaromanda X Jan 23 '18 at 22:17
  • 2
    what would've made this very clear for you is if, instead of `console.log(this.name);` you `console.log(this, this.name)` - then you'd see what `this` actually is, and in the case of `a` and `d` understand why the output is `blank` instead of `undefined` i.e. because `window.name` is a thing – Jaromanda X Jan 23 '18 at 22:20
  • I was going to edit this into a runnable snippet, however apparently `this.name` returns a `guid` in the editor, and doesn't really prove the point..... – Zze Jan 23 '18 at 22:30

2 Answers2

5

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).

Barmar
  • 596,455
  • 48
  • 393
  • 495
  • How would you change a and d so that they return "Anna" and "Denny" ? – Gundam Meister Jan 23 '18 at 22:20
  • I don't think you can. Don't use arrow functions if you want that. – Barmar Jan 23 '18 at 22:21
  • 3
    @GundamMeister - In other words, use the right tool for the job - in MDN documentation, it states *These function expressions are best suited for non-method functions* - your code is trying to use them as method functions – Jaromanda X Jan 23 '18 at 22:23
2

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: ƒ}
simon
  • 605
  • 7
  • 20
  • Thanks! Arrow function "this" and plain function "this" are pointing to different layer... interesting... – Gundam Meister Jan 23 '18 at 23:57
  • well in the above situation, the "layer" is actually window. it would only be on the functional layer, if a new instance of e were to exist, such as let echild = new e(); echild.func() – simon Jan 24 '18 at 00:32
  • i added also how the new keyword here can also change the behavior behind how this is treated. – simon Jan 24 '18 at 02:22