Reputation: 288
I may be wrong but my understanding is that this
var foo = {
'bar': x => x + 1,
'baz': function(y){ return this.bar(y); }
};
foo.baz(1);
should work fine since I took care not to define foo.baz
as an arrow function and so this
inside baz
is equal to foo
. Of course, when I test it on a console it works as I expected.
Now, I have a very similar setup with React in which this
gets undefined for some reason. This is the code:
const MapRoom = {
'getStyleFromCoords': coords => {
return { // account for borders
'left': coords[0] + 1,
'top': coords[1] + 1,
'width': (coords[2] - coords[0]) - 2,
'height':(props.coords[3] - props.coords[1]) - 2,
};
},
'Disabled': function(props){
console.log('this', this); // undefined
const style = this.getStyleFromCoords(props.coords); // error
return (
<div
className="room-selected"
style={style}
title={props.number}
></div>
);
}
}
and then
renderRooms(){
// stuff
return this.state.coords.map((coords, index) => {
// more stuff
if(disabled){
return (
<MapRoom.Disabled
key={roomNumber}
number={roomNumber}
coords={coords}
/>
);
} else if(...){}
});
}
render(){
return (
<stuff>
{this.renderRooms()}
</stuff>
);
}
I'd say they should be analagous, but it seems that's not the case. Of course this is not much problem since I can just move the function outside the object and then there's no need for this
to reference it, but I'm curious to know what is actually happening since I'm unable to reproduce the error.
In case it matters, I'm transpiling the code with Babel and the output is
var MapRoom = {
'getStyleFromCoords': function getStyleFromCoords(coords) {
return { // account for borders
'left': coords[0] + 1,
'top': coords[1] + 1,
'width': coords[2] - coords[0] - 2,
'height': coords[3] - coords[1] - 2
};
},
'Disabled': function Disabled(props) {
console.log('this', this);
var style = this.getStyleFromCoords(props.coords);
return __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement('div', {
className: 'room-selected',
style: style,
title: props.number
});
}
}
This is inside an anonymous function created by WebPack compiler.
Upvotes: 6
Views: 3962
Reputation: 161457
The this
value in a normal function
is set based on how the function is called. The structure of how the object is declared has no effect, it's just that foo.baz(1);
sets this
to foo
.
To break it down,
foo.baz(1);
is equivalent to
let _tmp = foo;
_tmp.baz.call(_tmp, 1);
where in this case the _tmp
could be pretty much skipped in place of just using foo
.
In your JSX case
<MapRoom.Disabled />
is doing
declareComponent(MapRoom.Disabled);
where that function just gets the function, e.g.
function declareComponent(someFunc){
someFunc();
}
By the time the function is called, it's just a function, there's no obj.someFunc
that would cause this
to be obj
, so it ends up being undefined
.
To clarify, the fact that your function is declared as a property on an object has no effect on anything, it is still just a function and it is up to you to ensure that the function is called with the proper this
value if you have a certain expectations. For instance you could do
const MapRoomDisabled = MapRoom.Disabled.bind(MapRoom);
<MapRoomDisabled />
and since the function has been bound with an explicit context, it would work as you expect.
But
var obj = {
prop: function(){}
};
is no different than
var obj = {
prop: null
};
obj.prop = function(){};
or
var someFunc = function someFunc(){}
var obj = {
prop: someFunc,
};
Upvotes: 4