开发者

Problem with prototypal inheritance and instance array [duplicate]

开发者 https://www.devze.com 2023-01-09 10:28 出处:网络
This question already has answers here: Javascript object members that are prototyped as arrays become shared by all class instances
This question already has answers here: Javascript object members that are prototyped as arrays become shared by all class instances (3 answers) Closed 8 years ago.

I use prototypal inheritance and want to have objects with instance arrays. So if I derive some objects from one object with an instance array and access the array, all of them share the array. I want to push something to the array and only change the array in the actual object, not in all others.

What is a elegent solution to this Problem with using standard prototypal inheritance and Object.create?

var sys = require('sys');

var obj ={
    data: [],
    add: function(what){
        this.data.push(what)
    }
};

var one = Object.create(obj);
one.add(1);

var other = Object.create(obj);
other.开发者_Python百科add(2);

sys.puts(other.data.length); // is 2, but should be 1


var ObjectName = function(){
    this.data = [];
}

ObjectName.prototype.add = function(what){
    this.data.push(what);
};

var one = new ObjectName();
one.add(1);


There is no elegant solution with Object.create, because You're Doing It Wrong.

What you want is:

function MyArray() {
    this.data = [];  // per-instance data here
}

MyArray.prototype = {
    add: function(what) {  // prototype methods here
        this.data.push(what);
    }
};

var one = new MyArray;
one.add(1);
...


You can also replace:

add: function(what) {  // prototype methods here
    this.data.push(what);
}

with

add: function(what) {  // prototype methods here
    this.data = this.data.concat(what);
}

as this will create a new variable instead of pushing it into it the prototype's instance.


Object.create can add properties to the new object, by passing a second parameter with property descriptors.

var sys = require('sys');

var obj = {
    add: function(what){
        this.data.push(what)
    }
};

var one = Object.create(obj, {
    data: {
        value: [],
        writable: true,
        enumerable: true,
        configurable: true
    }
});
one.add(1);

var other = Object.create(obj, {
    data: {
        value: [],
        writable: true,
        enumerable: true,
        configurable: true
    }
});
other.add(2);

sys.puts(other.data.length); // should be 1

Of course, you would want to put that in a builder function so you don't repeat yourself:

function makeThing() {
    return Object.create(obj, {
        data: {
            value: [],
            writable: true,
            enumerable: true,
            configurable: true
        }
    });
}

Although, at at point you're basically writing a constructor (with the advantage that you don't need to call it with new). Also, if you're setting writable, enumerable, and configurable to true, you could just set the property the normal way, which can be made backward-compatible with ECMAScript 3 by implementing a simple version of Object.create:

function makeThing() {
    var newObj = Object.create(obj);
    newObj.data = [];
    return newObj;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消