我现在才开始使用原型构造函数实例化JavaScript对象文字,但我对适用于我的情况的继承/反射规则感到有点困惑。
从本质上讲,我的问题是原型的原始对象有几层属性/值:
var protoObj = {
prop1: {
first : 1,
second : 2,
third : {
a : 'foo',
b : 'bar',
c : {
'love': true,
'babies': false,
'joy': undefined
}
}
},
prop2 : true
};...where除了少数属性外,所有这些属性在所有子对象中都将保持不变(并且应该动态更新)。
我可以为子对象更新或创建新的顶层属性,而不会影响原始原型对象:
if (typeof Object.create !== 'function') {
Object.create = function(o){
var F = function(){};
F.prototype = o;
return new F();
};
}
var someObj = Object.create(protoObj);
someObj.prop2 = false;
//protoObj.prop2 remains true
someObj.prop3 = [x,y,z];
//new property, unique to someObj (i.e. protoObj remains untouched)然而,如果我想在someObj中为根深蒂固的属性'joy'设置一个唯一的值,我似乎无法做到这一点,除非重新定义protoObj本身或将someObj的委托链中断回其原型:
someObj.prop1.third.c['joy'] = 'found';
//does not *directly* update someObj
//instead ends up setting the value of protoObj's property 'joy' to be 'found'
someObj.prop1 = {
first : 1,
second : 2,
third : {
a : 'foo',
b : 'bar',
c : {
'love': true,
'babies': false,
'joy': 'found'
}
}
};
//explicitly sets the above values in someObj.prop1 (including 'joy'), but breaks
//the prototypal link back to protoObj for all data in someObj.prop1 as well我怀疑我要么忽略了一个非常简单的解决方案,要么完全不走运,但不管怎样,我都会非常感谢你们所有人的意见。提前谢谢。
发布于 2011-02-02 10:06:36
简而言之:你在一定程度上运气不佳。
答案很长。当您从另一个对象创建原型对象时,您是在告诉JavaScript解释器,派生对象“看起来”像祖先对象。当你从一个属性中读取时,解释器知道如果需要,它可以遍历原型链。因此,对于:
var x = someObj.prop2;它首先查看someObj对象。它是否有一个名为prop2的属性?不,所以去看看原型对象。它是否有一个名为prop2的属性?是的,所以返回这个值。
当您设置一个属性时,它直接在对象中设置。这里不能走原型链。所以:
someObj.prop2 = true;表示在someObj中创建prop2属性并将其设置为true。在此之后,当您阅读prop2时,您将获得直接值,而无需遍历原型链。
现在,对于prop1,同样的事情也会发生。从someObj上阅读
var x = someObj.prop1;您将从prototype对象获得对象prop1,因为它在someObj中不存在。
但要注意:这是对propObj属性的引用。更改它的属性,您将为propObj更改它们。如果您确实需要对prop1进行更改,使其仅在someObj中可见,则您也必须将该对象原型化:
var someObj = Object.create(propObj);
someObj.prop1 = Object.create(propObj.prop1);
someObj.prop1.first = 42;在这里,最后一行将更改someObj.prop1中first的值,而不是propObj中的值。如果你需要走得更远,那就建立下一个层次的原型,以此类推。
发布于 2011-02-02 09:47:04
我想我明白了。
原型设计用于与所有实例共享方法。您似乎正在尝试使用prototype来为派生的someObj对象提供特定的实例成员。
但是为了理解为什么它是一个糟糕的解决方案,这里有原型是如何工作的:
当JS尝试resolve (保留)对象上的成员引用时,如果它在对象中找不到这个成员,它就在它的原型中查找(沿着原型链依此类推)。
因此,当你想要读取 someObj.prop1时,JS prop1 in someObj,它在它的原型protoObj中查找,并找到protoObj.prop1:
如上所述,这是完全正常的:
someObj.prop1.third.c['joy'] = 'found'...modifies原型,因为someObj.prop1 被解析为 protoObj.prop1
您忽略的一个小细节是,在做作中,JS不需要解析成员。当你写像这样的东西时:
someObj.stuff.other = 3JS解析someObj.stuff是因为您向.other询问它。
但当你键入时:
someObj.stuff = 3JS不会解决任何问题!!它只影响someObj的stuff成员,而根本不关心someObj或其原型中存在或不存在的东西。
如果内容在原型中有效,则同名的新成员将屏蔽原型成员。
从现在开始,您可能会明白,使用JS的原型来为实例提供成员值根本不是一个好的解决方案。相反,您应该考虑在函数构造函数本身中设置这些成员。例如:
function MyObj() {
this.prop1 = {first: 1, second: 2, third: {a: ...} }
this.prop2 = true;
}显然,每个实例都有自己的成员,与protoObj成员不同。
如果您希望使用原型为对象提供一些默认值和可变值,并且能够在通过实例修改这些值时“派生”这些值的一部分(一种写入时复制),这在JavaScript中是不可能的。
https://stackoverflow.com/questions/4869766
复制相似问题