-1

I'm trying to understand how arrow functions work in JS. One thing that confuses me is:

let obj1 = { // MDN states that object literal does not create a new scope but I didn't find 
             // any detailed explanation why
  name: "benny",
  getName: () => {
    console.log(this.name);
  },
};
obj1.getName(); // prints "undefined"

class myObj {
  constructor() {
    this.name = "benny";
    this.getName = () => {
      console.log(this.name);
    };
  }
}
let obj2 = new myObj();
obj2.getName(); //prints "benny"

Can somebody please explain why object literal does not create a new scope, while calling "new" does? (I always thought object literal and "new" operator are equal; I didn't find proper explanation in MDN.) I found this explanation on how new operator works. But it's not clear to me why object literal works differently.

Thanks in advance!

alexryabkov
  • 453
  • 1
  • 5
  • 7
  • See [Self-references in object literals / initializers](https://stackoverflow.com/q/4616202). Also note that the `myObj` constructor is ***not*** equivalent to an object literal, it's equivalent to `function myObj() { this.name = "benny"; this.getName = () => console.log(this.name); }` – VLAZ Nov 30 '20 at 09:37
  • Also relevant: [Arrow Function in Object Literal](https://stackoverflow.com/q/36717376) | [Methods in ES6 objects: using arrow functions](https://stackoverflow.com/q/31095710) – VLAZ Nov 30 '20 at 09:39
  • 1
    "*MDN states that object literal does not create a new scope but I didn't find any detailed explanation why*" because scopes are created when you call a function. Object literals are not function calls, same as how a literal `42` (number) or `"hello"` (string) also isn't. – VLAZ Nov 30 '20 at 09:47
  • I'm wondering why my question was downvoted? Is it too "stupid"? If yes I'm sorry but I'm still learning. – alexryabkov Nov 30 '20 at 10:07
  • Thanks @VLAZ for the explanation, it looks clear now. – alexryabkov Nov 30 '20 at 10:20

3 Answers3

3

The new operator doesn't create a new scope.

Functions create a new scope.

The constructor function is a different function to the global-outside-of-any-function space.

Quentin
  • 800,325
  • 104
  • 1,079
  • 1,205
2

So whenever you are using arrow function anywhere it will not have this of its own because it will refer this from its parent function(to be simple).

So in first case its referring this of window and hence undefined.

In second case is referring 'this' of constructor and hence 'benny'.

Vishal Bartakke
  • 294
  • 1
  • 9
1

class myObj {
  constructor() {
    this.name = "benny";
  }

  getName() {
    console.log(this.name);
  }

  getName2 = () => {
    console.log(this.name);
  }
}

let obj2 = new myObj();
obj2.getName();
obj2.getName2();

I wanted to bring up this example because I thought it was quite interesting -- this isn't meant as an answer to your question directly, but just some additional info.

People were talking about how defining it inside the constructor makes the this property refer to the object itself -- because that's what this means in a constructor! So I wanted to see what would happen if you define an arrow function in the way I've done above, with getName2 -- it's not in the constructor, but it still gets this defined as the object itself. So... why?

Well, it turns out when you define arrow functions in that manner, it actually DOES end up being defined in the constructor. I think there's some kind of code hoisting going on with arrow functions like that. You can actually verify it by trying to change the function on the prototype:

myObj.prototype.getName = () => {console.log('hello world')}
myObj.prototype.getName2 = () => {console.log('hello world')}
obj2.getName(); // this prints 'hello world'
obj2.getName2(); // this does not

You can't change the function of getName2 via the prototype, because that function actually gets defined in the constructor behind the scenes.

TKoL
  • 10,782
  • 1
  • 26
  • 50
  • 1
    "*I think there's some kind of code hoisting going on with arrow functions*" no, there isn't. Hoisting is a separate concept that is (partially) a by-product of how scripts are read and executed. A two-pass interpreter would first check the code for syntactic correctness. Part of that is watching for name clashes, so the first pass will initialise the bindings. The second pass then will execute the code using the defined bindings. It's that flow that leads to a "hoisting" behaviour. The "arrow methods" are [a field declaration (Stage 3 proposal)](https://github.com/tc39/proposal-class-fields) – VLAZ Nov 30 '20 at 11:58