This question already has an answer here:
-
Methods in ES6 objects: using arrow functions
4 answers
I\'m trying out ES6 and want to include a property inside my function like so
var person = {
name: \"jason\",
shout: () => console.log(\"my name is \", this.name)
}
person.shout() // Should print out my name is jason
However, when I run this code console only logs my name is
. What am I doing wrong?
Short answer: this
points at the nearest bound this
- in the code provided this
is found in the enclosing scope.
Longer answer: Arrow functions bind their this
when they are created do not have this
, arguments
or other special names bound at all - when the object is being created the name this
is found in the enclosing scope, not the person
object. You can see this more clearly by moving the declaration:
var person = {
name: \"Jason\"
};
person.shout = () => console.log(\"Hi, my name is\", this);
And even more clear when translated into a vague approximation of the arrow syntax in ES5:
var person = {
name: \"Jason\"
};
var shout = function() {
console.log(\"Hi, my name is\", this.name);
}.bind(this);
person.shout = shout;
In both cases, this
(for the shout function) points to the same scope as person
is defined in, not the new scope that the function is attached to when it is added to the person
object.
You cannot make arrow functions work that way, but, as @kamituel points out in his answer, you can take advantage of the shorter method declaration pattern in ES6 to get similar space savings:
var person = {
name: \"Jason\",
// ES6 \"method\" declaration - leave off the \":\" and the \"function\"
shout() {
console.log(\"Hi, my name is\", this.name);
}
};
Agreed with @Sean Vieira - in this case this
is bound to the global object (or, as pointed out in the comment, more generally to an enclosing scope).
If you want to have a shorter syntax, there is another option - enhanced object literals support short syntax for property functions. this
will be bound as you expect there. See shout3()
:
window.name = \"global\";
var person = {
name: \"jason\",
shout: function () {
console.log(\"my name is \", this.name);
},
shout2: () => {
console.log(\"my name is \", this.name);
},
// Shorter syntax
shout3() {
console.log(\"my name is \", this.name);
}
};
person.shout(); // \"jason\"
person.shout2(); // \"global\"
person.shout3(); // \"jason\"
Here the value of this inside of the function is determined by where the arrow function is defined not where it is used.
So this
refers to global/window object if not wrapped in other namespace
The accepted answer is excellent, concise, and clear but i will elaborate a little on what Sean Vieira said:
Arrow functions do not have
this arguments or other special names bound at all.
Because the arrow function doesn\'t have a \"this\", it uses the parent\'s \"this\". \"this\" always points to the parent, and the parent of the person object is Window (if you\'re in a browser).
To prove it run this in your console:
var person = {
name: \"Jason\",
anotherKey: this
}
console.log(person.anotherKey)
You\'ll get the Window object.
I find this to be a really helpful way to think about it. It isn\'t quite the full story, as what the \"this\" of an object literal is is another discussion.
The problem is that (MDN)
An arrow function expression [...] lexically binds the this value.
Arrow functions capture the this value of the enclosing context.
Therefore, the value of this
in that function will be the value of this
where you create the object literal. Probably, that will be window
in non-strict mode and undefined
in strict mode.
To fix it, you should use a normal function:
var person = {
name: \"jason\",
shout: function(){ console.log(\"my name is \", this.name) }
}
person.shout();