JavaScript - 独特地更新原型对象文字中的属性

发布于 2024-10-15 08:56:09 字数 1568 浏览 0 评论 0原文

我现在刚刚开始使用原型构造函数实例化 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小霸王臭丫头 2024-10-22 08:56:09

简短的回答:你部分运气不佳。

长答案。当您创建一个从另一个对象原型化的对象时,您是在告诉 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;

在这里,最后一行将更改值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:

var x = someObj.prop2;

It first looks at the someObj object. Does it have a property called prop2? No, so go look at the prototype object. Does it have a property called prop2? Yes, so return that value.

When you set a property, it gets set in the object directly. No walking the prototype chain here. So:

someObj.prop2 = true;

means that the prop2 property gets created in someObj and is set to true. After this point, when you read prop2 you will get the direct value and no walking the prototype chain.

Now with prop1 the same thing happens. Read it from someObj

var x = someObj.prop1;

and you will get the object prop1 from the prototype object, since it doesn't exist in someObj.

But watch out: this is a reference to propObj's property. Change its properties and you will change them for propObj. If you do need to make changes to prop1 such that those are only visible in someObj, you will have to prototype that object too:

var someObj = Object.create(propObj);
someObj.prop1 = Object.create(propObj.prop1);
someObj.prop1.first = 42;

Here, that last line will alter the value of first in someObj.prop1 and not the value in propObj. If you need to go deeper, then prototype the next level down and so on so forth.

無處可尋 2024-10-22 08:56:09

我想我明白了。

原型用于与所有实例共享方法。您似乎正在尝试使用原型为派生的 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解决任何问题!它只影响 3someObjstuff 成员,并且根本不关心 stuff 是否存在在 someObj 或其原型中。

如果东西有效地存在于原型中,则同名的新成员会掩盖原型成员。

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

function MyObj() {
  this.prop1 = {first: 1, second: 2, third: {a: ...} }
  this.prop2 = true;
}

显然每个实例都有自己的成员,与 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:

someObj.prop1.third.c['joy'] = 'found'

...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:

someObj.stuff.other = 3

JS resolves someObj.stuff because you are asking .other on it.

But when you type:

someObj.stuff = 3

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:

function MyObj() {
  this.prop1 = {first: 1, second: 2, third: {a: ...} }
  this.prop2 = true;
}

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文