Reputation: 1094
I was trying to understand the lexical scoping of 'this' in arrow functions. I tried the following code -
const obj1 = {
name: "obj1name",
method: function(){
return () => {return this.name};
}
};
const arrowFunc1 = obj1.method();
console.log(arrowFunc1());
const obj2 = {
name: "obj2name",
method: function(){
return obj1.method();
}
};
const arrowFunc2 = obj2.method();
console.log(arrowFunc2());
This gives the output -
obj1name
obj1name
As expected, 'this' inside the arrow function was lexically scoped to obj1 and hence it prints 'obj1name' no matter how we call it. All fine till here. Then instead of defining obj2.method I decided to directly copy obj1.method into it -
const obj1 = {
name: "obj1name",
method: function(){
return () => {return this.name};
}
};
const arrowFunc1 = obj1.method();
console.log(arrowFunc1());
const obj2 = {
name: "obj2name",
method: obj1.method
};
const arrowFunc2 = obj2.method();
console.log(arrowFunc2());
This gives the output -
obj1name
obj2name
I don't understand why it prints 'obj2name'.
My understanding is that the arrow function is defined in obj1.method and so it is lexically scoped in it. Hence it should take the value of 'this' from obj1.method which is obj1.
What am i getting wrong?
Upvotes: 0
Views: 148
Reputation: 8329
It is lexically scoped: you defined a function (arrow) in obj1, but called it in obj2 - the lexical scope of obj2 is obj2 - so the method you invoked there works as supposed to.
The console.logs in the snippet show the problem:
const obj1 = {
name: "obj1name",
method: function(){
return () => {return this.name};
}
};
const arrowFunc1 = obj1.method();
console.log(arrowFunc1());
const obj2 = {
name: "obj2name",
method: obj1.method
};
const arrowFunc2 = obj2.method();
console.log(arrowFunc2());
// these console.logs show your problem:
console.log('obj1:', obj1)
console.log('obj2:', obj2)
In your case, the function()
creates the scope for this
- and that function()
is in obj2
.
Maybe this snippet helps to understand a little more:
// extracted the function, but left the "this"
// just calling the function in itself would throw an
// error, but inside an object (that has a name property)
// it works nicely
const fn = function() {
return () => {
return this.name
}
}
const obj1 = {
name: "obj1name",
method: fn
};
const arrowFunc1 = obj1.method();
console.log(arrowFunc1());
const obj2 = {
name: "obj2name",
method: fn
};
const arrowFunc2 = obj2.method();
console.log(arrowFunc2());
// these console.logs show your problem:
console.log('obj1:', obj1)
console.log('obj2:', obj2)
And my last snippet:
const obj1 = {
name: "obj1name",
method: function() {
return () => {
return this.name
};
}
};
const arrowFunc1 = obj1.method();
console.log(arrowFunc1());
// if you want to call with obj1, then it's not enough to add the
// function - you have to CALL (invoke) it
const obj2 = {
name: "obj2name",
method: obj1.method()
};
// see that there're no parantheses after obj2.method - its
// value is resolved when creating obj2 by INVOKING the function
const arrowFunc2 = obj2.method;
console.log(arrowFunc2());
// these console.logs show your problem:
console.log('obj1:', obj1)
console.log('obj2:', obj2)
Upvotes: 1
Reputation: 13060
This:
const obj1 = {
name: "obj1name",
method: function(){
return () => {return this.name};
}
};
Should be this:
const obj1 = {
name: "obj1name",
method: () => {return this.name}
};
By wrapping the arrow function in a regular function the scope once again becomes the scope of the caller.
Upvotes: 1