JavaScript - 独特地更新原型对象文字中的属性
我现在刚刚开始使用原型构造函数实例化 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
本身或将 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
我怀疑我要么忽略了一个极其简单的解决方案,要么完全不走运,但无论如何,我都非常有必要听取你们的意见。提前致谢。
I'm just now getting into instantiating JavaScript object literals using a prototype constructor, but am a bit confused by the rules of inheritance/reflection which apply to my case.
Essentially my problem is that the original object that's being prototyped has several tiers of properties/values:
var protoObj = {
prop1: {
first : 1,
second : 2,
third : {
a : 'foo',
b : 'bar',
c : {
'love': true,
'babies': false,
'joy': undefined
}
}
},
prop2 : true
};
...where all but a select few of these properties will remain the same (and should be dynamically updated) in all child objects.
I can update or create new top-tier properties for the child objects without affecting the original prototype object just fine:
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)
If, however, I want to set a unique value for the deeply entrenched property 'joy'
in someObj
, I can't seem to do so without redefining protoObj
itself or breaking someObj
's delegation chain back to its prototype:
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
I suspect that I'm either overlooking an incredibly simple solution or altogether out of luck, but I'd be much obliged to hear from you all on this regardless. Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
简短的回答:你部分运气不佳。
长答案。当您创建一个从另一个对象原型化的对象时,您是在告诉 JavaScript 解释器派生对象“看起来像”祖先对象。当您读取属性时,解释器知道它可以在需要时遍历原型链。因此:
它首先查看
someObj
对象。它有一个名为prop2
的属性吗?不,所以去看看原型对象。它有一个名为prop2
的属性吗?是的,所以返回该值。当您设置属性时,它会直接在对象中设置。这里不走原型链。因此:
意味着
prop2
属性在someObj
中创建并设置为 true。在此之后,当您读取prop2
时,您将获得直接值,而无需遍历原型链。现在使用
prop1
也会发生同样的事情。从someObj
读取它,您将从原型对象中获取对象
prop1
,因为它在someObj
中不存在。但请注意:这是对
propObj
属性的引用。更改其属性,您将更改propObj
的属性。如果您确实需要对prop1
进行更改,以便这些更改仅在someObj
中可见,您也必须对该对象进行原型设计:在这里,最后一行将更改值
someObj.prop1
中的first
的值,而不是propObj
中的值。如果您需要更深入,请对下一个级别进行原型设计,依此类推。Short answer: you are partially out of luck.
Long answer. When you create an object prototyped from another, you are telling the JavaScript interpreter that the derived object "looks like" the ancestor object. When you read from a property, the interpreter knows that it can walk the prototype chain if need be. So for:
It first looks at the
someObj
object. Does it have a property calledprop2
? No, so go look at the prototype object. Does it have a property calledprop2
? Yes, so return that value.When you set a property, it gets set in the object directly. No walking the prototype chain here. So:
means that the
prop2
property gets created insomeObj
and is set to true. After this point, when you readprop2
you will get the direct value and no walking the prototype chain.Now with
prop1
the same thing happens. Read it fromsomeObj
and you will get the object
prop1
from the prototype object, since it doesn't exist insomeObj
.But watch out: this is a reference to
propObj
's property. Change its properties and you will change them forpropObj
. If you do need to make changes toprop1
such that those are only visible insomeObj
, you will have to prototype that object too:Here, that last line will alter the value of
first
insomeObj.prop1
and not the value inpropObj
. If you need to go deeper, then prototype the next level down and so on so forth.我想我明白了。
原型用于与所有实例共享方法。您似乎正在尝试使用原型为派生的 someObj 对象提供特定的实例成员。
但要理解为什么这是一个糟糕的解决方案,请了解原型设计的工作原理:
当 JS 尝试解析(保留)对象上的成员引用时,如果在对象中找不到该成员,它会查找在它的原型中(沿着原型链依此类推)。
所以当你想读取 someObj.prop1时,JS在someObj中没有找到prop1,它会在它的原型protoObj中查找,并找到protoObj.prop1:
如此说来,这完全是正常情况是:
...修改原型,因为 someObj.prop1 被解析为 protoObj.prop1
您忽略的一些细节是,在做作中,JS 不需要解析 会员。当你写这样的东西时:
JS解析了someObj.stuff,因为你在它上面询问.other。
但是当你输入:
JS不解决任何问题!它只影响 3 到 someObj 的 stuff 成员,并且根本不关心 stuff 是否存在在 someObj 或其原型中。
如果东西有效地存在于原型中,则同名的新成员会掩盖原型成员。
从现在开始,您可能会明白,使用 JS 的原型来为实例赋予成员值根本不是一个好的解决方案。相反,您应该考虑在函数构造函数本身中设置这些成员。例如:
显然每个实例都有自己的成员,与 protoObj 的成员不同。
如果您想使用原型为您的对象提供一些默认和可变的值,并且当您通过实例修改它们时能够“分叉”这些值的一部分(一种写时复制),那么这只是在 JavaScript 中是不可能的。
I think i got it.
Prototyping is used to share methods with all instances. It seems like you are trying to use prototype to give particular instance members to the derivated someObj object.
But to understand why it's a bad solution, here how prototyping works:
When JS try to resolve (retain that) a member reference on an object, if it does not find this member in the object, it looks in its prototype (and so on along the prototype chain).
So when you want to read someObj.prop1, JS does not find prop1 in someObj, it looks in its prototype protoObj, and find protoObj.prop1:
Thus said, it's totally normal that:
...modifies the prototype because someObj.prop1 is resolved as protoObj.prop1
The slightly detail you are ignoring is that in an affectation, JS doesn't necessary resolve the member. When you write stuff like:
JS resolves someObj.stuff because you are asking .other on it.
But when you type:
JS does not resolve anything!! It just affects 3 to the stuff member of someObj and dont care at all about the existence or nonexistence of stuff in someObj or in its prototype.
If stuff was effectively in the prototype, the new member of the same name masks the prototype one.
From now, you may understand that using the prototyping of JS to give member values to the instances is not a good solution at all. Instead, you should consider setting these members in the function constructor itself. For instance:
Obviously each instance has its own members distinct from protoObj ones.
If you want to use prototyping to provide some default and mutable values to your objects, and be able to "fork" a part of these values when you modify them through an instance (a sort of copy-on-write), this is just impossible in JavaScript.