Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
169 views
in Technique[技术] by (71.8m points)

javascript - Crockford's Prototypal inheritance - Issues with nested objects

I've been reading "Javascript: The Good Parts" by Douglas Crockford - and while it's a bit extreme, I'm on board with a lot of what he has to say.

In chapter 3, he discusses objects and at one point lays out a pattern (also found here) for simplifying & avoiding some of the confusion/issues that come with the use of the built-in "new" keyword.

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
newObject = Object.create(oldObject);

So I've tried using this in a project I'm working on, and I noticed an issue when attempting to inherit from objects that are nested. If I overwrite a value of a nested object inherited using this pattern, it overwrites the nested element all the way up the prototype chain.

Crockford's example is like the flatObj in the following example, which works well. The behaviour, however, is inconsistent with nested objects:

var flatObj = {
    firstname: "John",
    lastname: "Doe",
    age: 23
}
var person1 = Object.create(flatObj);

var nestObj = {
    sex: "female",
    info: {
        firstname: "Jane",
        lastname: "Dough",
        age: 32  
    }
}
var person2 = Object.create(nestObj);

var nestObj2 = {
    sex: "male",
    info: {
        firstname: "Arnold",
        lastname: "Schwarzenneger",
        age: 61  
    }
}
var person3 = {
    sex: "male"
}
person3.info = Object.create(nestObj2.info);

// now change the objects:
person1.age = 69;
person2.info.age = 96;
person3.info.age = 0;

// prototypes should not have changed:
flatObj.age // 23
nestObj.info.age // 96 ???
nestObj2.info.age // 61

// now delete properties:
delete person1.age;
delete person2.info.age;
delete person3.info.age;

// prototypes should not have changed:
flatObj.age // 23
nestObj.info.age // undefined ???
nestObj2.info.age // 61

(also on a fiddle)

Am I doing something wrong, or is this a limitation of this pattern?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is no inconsistency. Just don't think of nested objects: a direct property of an object is always either on its prototype or an own property. It's irrelevant wheter the property value a primitive or an object.

So, when you do

var parent = {
    x: {a:0}
};
var child = Object.create(parent);

child.x will be referencing the same object as parent.x - that one {a:0} object. And when you change a property of it:

var prop_val = child.x; // == parent.x
prop_val.a = 1;

both will be affected. To change a "nested" property independently, you first will have to create an independent object:

child.x = {a:0};
child.x.a = 1;
parent.x.a; // still 0

What you can do is

child.x = Object.create(parent.x);
child.x.a = 1;
delete child.x.a; // (child.x).a == 0, because child.x inherits from parent.x
delete child.x; // (child).x.a == 0, because child inherits from parent

which means they are not absolutely independent - but still two different objects.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...