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;
}
精彩评论