Hailwood
Hailwood

Reputation: 92621

new instance of object acting as reference?

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

Answers (3)

Abdullah
Abdullah

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

RobG
RobG

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

I Hate Lazy
I Hate Lazy

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

Related Questions