我现在正在使用原型构造函数实例化JavaScript对象文字,但是对于适用于我的情况的继承/反射规则有点困惑。
基本上我的问题是原型的原始对象有几层属性/值:
var protoObj = {
prop1: {
first : 1,
second : 2,
third : {
a : 'foo',
b : 'bar',
c : {
'love': true,
'babies': false,
'joy': undefined
}
}
},
prop2 : true
};
...除了这些属性中的一小部分外,所有子对象中的所有属性都将保持不变(并且应该动态更新)。
我可以为子对象更新或创建新的顶层属性,而不会影响原始原型对象:
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)
但是,如果我想为'joy'
中根深蒂固的属性someObj
设置唯一值,我似乎无法在不重新定义protoObj
本身或打破{{}}的情况下这样做{1}}代表团回到原型:
someObj
我怀疑我要么忽略了一个非常简单的解决方案,要么完全没有运气,但无论如何,我都不得不听到你们所有人的意见。提前谢谢。
答案 0 :(得分:2)
简短回答:你运气不好。
答案很长。当您从另一个创建对象原型时,您告诉JavaScript解释器派生对象“看起来像”祖先对象。当您从属性中读取时,解释器知道如果需要它可以走原型链。所以:
var x = someObj.prop2;
首先查看someObj
对象。它有一个名为prop2
的属性吗?不,所以去看看原型对象吧。它有一个名为prop2
的属性吗?是的,所以返回那个价值。
设置属性时,它会直接在对象中设置。不要在这里走原型链。所以:
someObj.prop2 = true;
表示prop2
属性在someObj
中创建,并设置为true。在此之后,当您阅读prop2
时,您将获得直接值并且不会走原型链。
现在prop1
同样的事情发生了。从someObj
var x = someObj.prop1;
,您将从原型对象中获取对象prop1
,因为someObj
中不存在该对象。
但请注意:这是对propObj
财产的引用。更改其属性,您将为propObj
更改它们。如果您确实需要对prop1
进行更改,以便仅在someObj
中显示这些更改,那么您也必须对该对象进行原型设计:
var someObj = Object.create(propObj);
someObj.prop1 = Object.create(propObj.prop1);
someObj.prop1.first = 42;
此处,最后一行将改变first
中someObj.prop1
的值,而不是propObj
中的值。如果你需要更深入,那么将下一个级别原型化,依此类推。
答案 1 :(得分:1)
我想我明白了。
原型设计用于与所有实例共享方法。您似乎正在尝试使用原型将特定实例成员提供给派生的someObj对象。
但要理解为什么这是一个糟糕的解决方案,原型如何运作:
当JS尝试解析(保留)对象的成员引用时,如果它在对象中找不到该成员,则会查看其原型(依此类推原型链) )。
所以当你想要读取 someObj.prop1时,JS会在someObj中找到而不是找到prop1,它会在原型protoObj中查找,并找到protoObj.prop1:
如此说,这是完全正常的:
someObj.prop1.third.c['joy'] = 'found'
...修改原型,因为someObj.prop1 被解析为 protoObj.prop1
您忽略的一个细节是,在做作中,JS不必解决成员。当你写下这样的东西时:
someObj.stuff.other = 3
JS解析someObj.stuff,因为你要求 .other 。
但是当你输入:
someObj.stuff = 3
JS 不解决任何问题!它只会影响 3 到 someObj 的 stuff 成员,并且根本不关心 stuff 的存在与否在 someObj 或其原型中。
如果 stuff 在原型中有效,那么同名的新成员会掩盖原型。
从现在开始,您可能会理解使用JS的原型来为实例提供成员值并不是一个好的解决方案。相反,您应该考虑在函数构造函数本身中设置这些成员。例如:
function MyObj() {
this.prop1 = {first: 1, second: 2, third: {a: ...} }
this.prop2 = true;
}
显然,每个实例都有自己的成员,与protoObj不同。
如果要使用原型设计为对象提供一些默认值和可变值,并且能够在通过实例修改它们时“分叉”这些值的一部分(一种写时复制),这在JavaScript中是不可能的。