首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >JavaScript -唯一地更新原型化对象文字中的属性

JavaScript -唯一地更新原型化对象文字中的属性
EN

Stack Overflow用户
提问于 2011-02-02 09:06:19
回答 2查看 411关注 0票数 3

我现在才开始使用原型构造函数实例化JavaScript对象文字,但我对适用于我的情况的继承/反射规则感到有点困惑。

从本质上讲,我的问题是原型的原始对象有几层属性/值:

代码语言:javascript
运行
复制
var protoObj = {  
  prop1: {  
    first : 1,
    second : 2,
    third : {  
      a : 'foo',
      b : 'bar',
      c : {  
        'love': true,  
        'babies': false,
        'joy': undefined
      }
    } 
  },  
  prop2 : true       
};

...where除了少数属性外,所有这些属性在所有子对象中都将保持不变(并且应该动态更新)。

我可以为子对象更新或创建新的顶层属性,而不会影响原始原型对象:

代码语言:javascript
运行
复制
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的委托链中断回其原型:

代码语言:javascript
运行
复制
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

我怀疑我要么忽略了一个非常简单的解决方案,要么完全不走运,但不管怎样,我都会非常感谢你们所有人的意见。提前谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-02-02 10:06:36

简而言之:你在一定程度上运气不佳。

答案很长。当您从另一个对象创建原型对象时,您是在告诉JavaScript解释器,派生对象“看起来”像祖先对象。当你从一个属性中读取时,解释器知道如果需要,它可以遍历原型链。因此,对于:

代码语言:javascript
运行
复制
var x = someObj.prop2;

它首先查看someObj对象。它是否有一个名为prop2的属性?不,所以去看看原型对象。它是否有一个名为prop2的属性?是的,所以返回这个值。

当您设置一个属性时,它直接在对象中设置。这里不能走原型链。所以:

代码语言:javascript
运行
复制
someObj.prop2 = true;

表示在someObj中创建prop2属性并将其设置为true。在此之后,当您阅读prop2时,您将获得直接值,而无需遍历原型链。

现在,对于prop1,同样的事情也会发生。从someObj上阅读

代码语言:javascript
运行
复制
var x = someObj.prop1;

您将从prototype对象获得对象prop1,因为它在someObj中不存在。

但要注意:这是对propObj属性的引用。更改它的属性,您将为propObj更改它们。如果您确实需要对prop1进行更改,使其仅在someObj中可见,则您也必须将该对象原型化:

代码语言:javascript
运行
复制
var someObj = Object.create(propObj);
someObj.prop1 = Object.create(propObj.prop1);
someObj.prop1.first = 42;

在这里,最后一行将更改someObj.prop1first的值,而不是propObj中的值。如果你需要走得更远,那就建立下一个层次的原型,以此类推。

票数 2
EN

Stack Overflow用户

发布于 2011-02-02 09:47:04

我想我明白了。

原型设计用于与所有实例共享方法。您似乎正在尝试使用prototype来为派生的someObj对象提供特定的实例成员。

但是为了理解为什么它是一个糟糕的解决方案,这里有原型是如何工作的:

当JS尝试resolve (保留)对象上的成员引用时,如果它在对象中找不到这个成员,它就在它的原型中查找(沿着原型链依此类推)。

因此,当你想要读取 someObj.prop1时,JS prop1 in someObj,它在它的原型protoObj中查找,并找到protoObj.prop1:

如上所述,这是完全正常的:

代码语言:javascript
运行
复制
someObj.prop1.third.c['joy'] = 'found'

...modifies原型,因为someObj.prop1 被解析为 protoObj.prop1

您忽略的一个小细节是,在做作中,JS不需要解析成员。当你写像这样的东西时:

代码语言:javascript
运行
复制
someObj.stuff.other = 3

JS解析someObj.stuff是因为您向.other询问它。

但当你键入时:

代码语言:javascript
运行
复制
someObj.stuff = 3

JS不会解决任何问题!!它只影响someObj的stuff成员,而根本不关心someObj或其原型中存在或不存在的东西。

如果内容在原型中有效,则同名的新成员将屏蔽原型成员。

从现在开始,您可能会明白,使用JS的原型来为实例提供成员值根本不是一个好的解决方案。相反,您应该考虑在函数构造函数本身中设置这些成员。例如:

代码语言:javascript
运行
复制
function MyObj() {
  this.prop1 = {first: 1, second: 2, third: {a: ...} }
  this.prop2 = true;
}

显然,每个实例都有自己的成员,与protoObj成员不同。

如果您希望使用原型为对象提供一些默认值和可变值,并且能够在通过实例修改这些值时“派生”这些值的一部分(一种写入时复制),这在JavaScript中是不可能的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4869766

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档