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.
It means that the this. value in the event handler always returns undefined . As mentioned earlier, the arrow function doesn't have its own this value. It uses the this value of the enclosing lexical scope.
In short, with arrow functions there are no binding of this . In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever. With arrow functions the this keyword always represents the object that defined the arrow function.
The attribute onClick just stores a reference to that function. Whenever a user clicks on the button, that referenced function is called on the global object. So the keyword this is set to undefined in the strict mode. To resolve this, you have to bind the increaseCounter() to this in the constructor.
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,
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With