54

When ES6 Arrow functions don't seem to work for assigning a function to an object with prototype.object. Consider the following examples:

function Animal(name, type){
 this.name = name;
  this.type = type;
  this.toString = () => `${this.name} is a ${this.type}`;

}
var myDog = new Animal('Max', 'Dog');
console.log(myDog.toString()); //Max is a Dog

Using the arrow function explicitly in the object definition works, but using the arrow functions with the Object.prototype syntax does not:

function Animal2(name, type){
  this.name = name;
  this.type = type;
}
Animal2.prototype.toString = () => `${this.name} is a ${this.type}`;

var myPet2 = new Animal2('Noah', 'cat');
console.log(myPet2.toString()); //is a undefined

Just as a proof of concept, using the Template string syntax with Object.prototype syntax does work:

function Animal3(name, type){
  this.name = name;
  this.type = type;
}
Animal3.prototype.toString = function(){ return `${this.name} is a ${this.type}`;}

var myPet3 = new Animal3('Joey', 'Kangaroo');
console.log(myPet3.toString()); //Joey is a Kangaroo

Am I missing something obvious? I feel that example 2 should work logically, but I am puzzled by the output. I'm guessing it is a scoping issue, but I am thrown off by the output 'is a undefined'.

ES6 Fiddle

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Jonathan Lucas
  • 545
  • 1
  • 4
  • 6
  • possible duplicate of [Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?](http://stackoverflow.com/q/34361379/1048572) – Bergi Jun 01 '16 at 01:53
  • 12
    @Bergi My question was posted 10 months ago and has 0 upvotes. How could it possibly be a duplicate of a question posted 5 months ago, and why is it important to decide that now? – Jonathan Lucas Jun 01 '16 at 19:27
  • 7
    There is no blame assigned here (notice I also didn't close the question but only posted a comment). The only important thing is that future readers are directed to the very helpful canonical post on this topic, and that's why I linked it. – Bergi Jun 01 '16 at 19:34

4 Answers4

50

Arrow functions provide a lexical this. It uses the this that is available at the time the function is evaluated.

It is logically equivalent to (the following isn't valid code since you can't have a variable named this):

(function(this){
   // code that uses "this"
 })(this)

In your 1st example the arrow function is within the constructor, and this points to the newly generated instance.

In your 3rd example, an arrow function isn't used and standard this behavior works as always (the this in the function scope).

In your 2nd example, you use an arrow function but at the scope it's evaluated, this is global / undefined.

Amit
  • 45,440
  • 9
  • 78
  • 110
  • So is it not possible to use this with Arrow Functions outside of the constructor (Example 2)? – Jonathan Lucas Jul 31 '15 at 21:35
  • 1
    You could use it in any place where `this` is the `this` you intend it to be. For example, suppose your object had a `setup()` function that adds multiple functions to itself, and you'd call it like this: `myObj.setup()`. That function could use arrow functions to add the needed functions. Another, more typical use case is where using callback functions that need access to `this` of the initiating context. – Amit Jul 31 '15 at 21:39
  • 10
    *"Arrow functions provide a lexical this"* More accurate would be to say that arrow functions do not provide a `this`, so instead of from its own lexical scope, it comes from the outer lexical scope. –  Oct 09 '16 at 16:56
  • 5
    I would argue it's more equivalent to `function(){}.bind(this)`. It's pre-bound to the `this` of the scope it was created in. This is helpful in e.g. event listeners where we often want to use stuff from the surrounding scope inside the listener. In es5 code it means doing `var me = this` before attaching the listener or using `bind`. – Stijn de Witt Apr 17 '17 at 21:28
  • *"It uses the `this` that is available at the time the function is evaluated."* is misleading. Suggest: *"It uses the `this` that is present in the context where the function is created."* Or even better: *"Arrow functions don't have their own `this` at all. They close over the `this` of the context where they are created, just like closing over a variable where they're created. (They also close over `arguments` and, where relevant, `super`.)"* – T.J. Crowder Feb 07 '18 at 15:02
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions – xgqfrms Aug 21 '19 at 01:28
5

Regular function returns a reference to the current JavaScript Object but the arrow function returns the reference to the global window object.

Regular functions are working well with objects using the new keyword. They have the constructor function by which values can be initialized during object creation. It can be managed using the prototype chaining but the arrow function does not have constructor function, prototype chaining. They are not working well with objects. They can not be used with the new keyword for assigning memory.

In your first example, you write your arrow key function inside the regular function, then you will get the output.

function Animal2(name, type){
    this.name = name;
    this.type = type;
}
Animal2.prototype.toString = function(){
    return () => `${this.name} is a ${this.type}`;
}

var myPet2 = new Animal2('Noah', 'cat');
console.log(myPet2.toString()()); //Noah is a cat

Reference: Difference between regular function and arrow key function

matthias_h
  • 11,356
  • 9
  • 22
  • 40
0

arrow function is not have its own this , it resolved to this of closest function:

  • your 1st example: this resolve to this of Animal() function
  • your 2nd example: this resolve to global object window (because it isn't inside any function)
  • your 3rd example: this working as always expected because not using arrow funciton.
0

It should be noted that the arrow function doesn't have this for itself and always the this keyword in each arrow function refers to lexical scope, so in your first example, the this keyword refers to the Animal class. In your 2nd example, the this keyword refers to the global scope. In the 3rd example, because the toString method belongs to the Animal class prototype, therefore it has access to the Animal class scope, in other words, the this keyword inside a prototype's methods refers to the prototype owner.

here there are some useful links:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

RBT
  • 24,161
  • 21
  • 159
  • 240
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 14 '22 at 14:59