According to following code, I have a small problem with accessing this
variable in prototypes.
var MyClass = function(number) {
this.number = number || 4;
};
MyClass.prototype = {
run: function() {
//direct access to object
console.log(this.number);
//access to object with the "self" object
var self = this;
setTimeout(function() {
console.log(self.number);
}, 1000);
//access to object with the "self" object as a parameter
this.events.test_a(self);
//here is the problem
this.events.test_b();
},
events: {
test_a: function(self) {
//access to object with the "self" object as a parameter
console.log(self.number);
},
test_b: function() {
console.log(this.number); // 👈 The problem
}
}
};
//----
var myClass = new MyClass(110);
myClass.run();
Is there any way to access the this
object and having some structure like following?
myClass.events.test_b();
I need this👆 without using the instance that I've just created like following:👇
myClass.events.test_a(myClass);
In general, you're best off avoiding designing the structure that way.
But you can do it by binding the events
functions in the constructor, which means creating an "own" copy of the events object. See ***
comments in this minimal-changes version:
// NOTE: Sticking to ES5 as the OP seems to be doing that
var MyClass = function(number) {
this.number = number || 4;
// *** Bind the functions on `this.events` to `this`
var self = this;
var events = self.events;
self.events = {};
Object.keys(events).forEach(function(key) {
if (typeof events[key] === "function") {
self.events[key] = events[key].bind(self);
}
});
};
// I've added the "name" parameter that's being passed around
// so we can be sure that the results for multiple
// instances are correct
MyClass.prototype = {
constructor: MyClass, // *** Don't break prototype.constructor
run: function(name) {
//direct access to object
console.log(name, "Direct access in object:", this.number);
//access to object with the "self" object
var self = this;
setTimeout(function() {
console.log(name, "In setTimeout callback:", self.number);
}, 1000);
//access to object with the "self" object as a parameter
this.events.test_a(name, self);
//here is the problem
this.events.test_b(name);
},
events: {
test_a: function(name, self) {
//access to object with the "self" object as a parameter
console.log(name, "In test_a:", self.number);
},
test_b: function(name) {
console.log(name, "In test_b:", this.number); // 👈 Not a problem anymore
}
}
};
//----
var mc1 = new MyClass(110);
var mc2 = new MyClass(220);
setTimeout(function() {
mc1.run("mc1");
}, 1000);
setTimeout(function() {
mc2.run("mc2");
}, 2000);
.as-console-wrapper {
max-height: 100% !important;
}
Side note: See this line I added to the object you're assigning to prototype
:
constructor: MyClass, // *** Don't break prototype.constructor
By default, the prototype
object on a function has a constructor
property pointing back to the function, so best to do that.