I'm an experienced coder learning JavaScript for the first time, using Douglas Crockford's "Javascript: The Good Parts" book. In it, he recommends using a 'purely prototypal' approach to inheritance, using this function:
if (typeof Object.create !== 'function') {
Object.create = function(o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
The problem I'm having is that when an object has a property that's an object rather than a simple type, creating a new object inherits the parent's instance of that object, rather than creating a new one. For example:
var aBody = {
arms : 2,
legs : 2
};
var person = {
name : 'Jeff',
body : Object.create(aBody)
};
document.writeln('Person '+person.name+' has '+person.body.arms+' arms and '+person.body.legs+' legs.');
var cat = Object.create(person);
cat.name = 'Bob';
cat.body.arms = 0;
cat.body.legs = 0;
document.writeln('Cat '+cat.name+' has '+cat.body.arm开发者_高级运维s+' arms and '+cat.body.legs+' legs.');
document.writeln('Now person '+person.name+' has '+person.body.arms+' arms and '+person.body.legs+' legs.');
This has output:
Person Jeff has 2 arms and 2 legs.
Cat Bob has 0 arms and 0 legs.
Now person Jeff has 0 arms and 0 legs.
I get the expected behaviour for the simple 'name' property, but not for the 'body'. I think I understand - because JavaScript is copying by reference, no new instance of aBody is spawned. I could manually do this each time I create an object from person
with e.g. cat.body = Object.create(aBody)
but I haven't managed to find a neat way to roll this into the original object definition (here, person
).
I'd really appreciate any guidance you could offer, as I'm trying to learn to write nice, clear, reliable JS code. Is there a clever technique people using the 'purely prototypal' approach have for handling this problem?
The whole point of a prototype object is to provide a place to house class-global properties. Thus, the behavior your seeing is in fact the feature that prototypal inheritance is intended to support.
If you don't want instances to share properties, put the properties directly on the instances.
I would generalize Crock's function to check for an intialization method:
if (typeof Object.create !== 'function') {
Object.create = function(o) {
var F = function () {};
F.prototype = o;
var obj = new F();
if (o.init && typeof o.init === 'function')
o.init.call(obj);
return obj;
};
}
No you can modify "aBody":
var aBody = {
init: function() {
this.body = { arms: 2, legs: 2 };
}
};
When you create instances with that, they'll have their own "body" property.
精彩评论