Reputation: 92621
I am having a problem creating new instances of an object.
Using the below code I was expecting each element to have it's own random value (which is happening).
But then I was also expecting the this.element
value to be contained to each instance of the object, but instead every time the value is changed in any instance of the object it is updating in all of them.
var Instance = function(element) {
this.$element = $(element);
this.subInstance.parent = this;
}
Instance.prototype = {
subInstance: {
parent: null,
$element: null,
init: function() {
var $this = this;
this.$element = this.parent.$element;
//test for what this.$element refers to in init function
var random = Math.random();
$('.element', this.$element).text('Updated ' + random);
//test for what this.$element refers to in an event handler
$('.element', this.$element).on('click', function(e) {
$this.$element.css('background-color', '#f00');
});
}
}
}
$('div.instance').each(function(i, o) {
var instance = new Instance(o);
instance.subInstance.init();
});
Now I know I could move subInstance out of the prototype and into the constructor using this.subInstance = {...
but that seems wrong, why is this.$element
not contained to each instance of the object?
JSFiddle of both examples: http://jsfiddle.net/q7zAg/
Upvotes: 0
Views: 809
Reputation: 998
var Obj =
{
internal:null,
__init:function(data){
this.internal = data;
return this
},
get:function(){
return this.internal;
},
init:function(){
var args = arguments,instance = function(){
return this.__init.apply(this,args);
};
instance.prototype = this;
return new instance();
}
}
console.log(Obj.init(123).get());
console.log(Obj.get());
console.log(Obj.init(321).get());
console.log(Obj.get());
Upvotes: 0
Reputation: 147413
Note that a function's this
is set by how the function is called, not how it's declared or initialised (other than using bind).
In your code you have:
> Instance.prototype = {
> subInstance: {
which assigns an object to Instance.prototype
that has a subInstance
property that is an Object.
Then there is:
> init: function() {
> var $this = this;
> this.$element = this.parent.$element;
The method is called as:
> instance.subInstance.init();
So this
within the init
method always references the same object (i.e. Instance.prototype.subInstance
), so assignments to this.$element
keep replacing the value.
Upvotes: 0
Reputation: 48771
It may seem wrong, but it's not. If each object created from the constructor needs to work with a unique subInstance
, you'll need to create a new one for each individual instance. On the prototype
it will be shared.
However, one thing you could do would be to use Object.create
to create a new instance that inherits from the prototyped subInstance
. Then you get the benefit of some reuse, and each instance can modify its own object.
var Instance = function(element) {
this.$element = $(element);
this.subInstance = Object.create(this.subInstance);
this.subInstance.parent = this;
}
Now some may argue that the subInstance
still shouldn't be on the prototype
, but rather should be a local variable in an IIFE. I would tend to agree with this.
Here's an example:
var Instance = (function() {
var _subInstance = {
parent: null,
$element: null,
init: function() {
// ...
}
};
var Instance = function(element) {
this.$element = $(element);
this.subInstance = Object.create(_subInstance);
this.subInstance.parent = this;
};
// other prototyped props
Instance.prototype.foo = "bar";
return Instance;
})();
Upvotes: 1