JavaScript - 在原型对象文字中唯一更新属性

时间:2011-02-02 01:06:19

标签: javascript object prototype

我现在正在使用原型构造函数实例化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

我怀疑我要么忽略了一个非常简单的解决方案,要么完全没有运气,但无论如何,我都不得不听到你们所有人的意见。提前谢谢。

2 个答案:

答案 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;

此处,最后一行将改变firstsomeObj.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中是不可能的。