Good day
I recently ran into a strange situation where my this
value in on a member function of a class is undefined. I know there are a lot of questions relating undefined this
contexts, but I can't find any explanation of this issue. I would love to know why it happens. In this examples, why does the arrow function implementation of the setModified
function keep its this context, but the function on the class does not.
This example breaks in the setModified
function on the block class
class point {
constructor(x, y) {
this._x = x || 0;
this._changeEvents = [];
}
set changeEvent(eventFunction) {
this._changeEvents.push(eventFunction);
}
set x(value) {
this._x = value;
this.runChangeEvent();
}
set y(value) {
this._y = value;
this.runChangeEvent();
}
get x() {
return this._x;
}
get y() {
return this._y;
}
runChangeEvent() {
this._changeEvents.forEach(event => event(this));
}
}
class renderItem {
constructor(canvas) {
this._canvas = canvas;
}
render(){
}
}
class block extends renderItem {
constructor(canvas) {
super(canvas);
this._modified = true;
this._topLeft = new point(0, 0);
this._topLeft.changeEvent = this.setModified;
}
//Using a method on the class as a callback, it breaks
setModified(){
this._modified = true;//breaks, this is undefined
console.log(this);
}
//Sets
set topLeft(value) { this._topLeft = value; }
//Gets
get topLeft() { return this._topLeft }
}
//Creates an instance of the block
const bl = new block(null);
bl.topLeft.x = 20;
But when you change setModified
function to an arrow function (also on the class), it works:
class point {
constructor(x, y) {
this._x = x || 0;
this._y = y || 0;
this._changeEvents = [];
}
set changeEvent(eventFunction) {
this._changeEvents.push(eventFunction);
}
set x(value) {
this._x = value;
this.runChangeEvent();
}
set y(value) {
this._y = value;
this.runChangeEvent();
}
get x() {
return this._x;
}
get y() {
return this._y;
}
runChangeEvent() {
this._changeEvents.forEach(event => event(this));
}
}
class renderItem {
constructor(canvas) {
this._canvas = canvas;
}
render(){
}
}
class block extends renderItem {
constructor(canvas) {
super(canvas);
this._modified = true;
//Using an arrow function on the class instance as a callback, it works
this.setModified = () => {
this._modified = true;//works
console.log(this);
};
this._topLeft = new point(0, 0);
this._topLeft.changeEvent = this.setModified;
}
//Sets
set topLeft(value) { this._topLeft = value; }
//Gets
get topLeft() { return this._topLeft }
}
const bl = new block(null);
bl.topLeft.x = 20;
Why would the member function on the class lose the this context but not the arrow function?