我尝试实现对象继承,其中每个对象共享相同的功能但包含不同的值/容器。这样做我发现了一种奇怪的行为;每个单独的对象都像魅力一样,但它们都有相同的选择。请澄清我的意思,我添加了一个示例代码。
我想要做的是从每个元素中读取数据值并将其绑定到选项。在某些功能中需要这些才能正常工作!
<div class="first" data-value="first div"></div>
<div class="second" data-value="second div"></div>
<script>
var original = {
options: {
value: null,
factor: 13
},
init: function (container) {
this.options.value = container.getAttribute('data-value');
}
};
var variation = Object.create(original);
variation.options.factor = 37;
var firstDiv = Object.create(variation);
var secondDiv = Object.create(variation);
firstDiv.init(document.getElementsByTagName('div')[0]);
secondDiv.init(document.getElementsByTagName('div')[1]);
alert('firstDiv.options === secondDiv.options: ' + (firstDiv.options === secondDiv.options)); // but should be false!
</script>
请注意,这只是显示实际物体的一小部分。在我看来,所有其他部分都是无关紧要的。
我希望它清楚问题是什么。另外我故意使用Object.create()
。
答案 0 :(得分:5)
对象包含相同的值,但不应该
他们应该,因为你没有更改options
上的variation
属性,所以它仍然指向original.options
指向的同一个对象。
执行此操作时:
var original = {
options: {
value: null,
factor: 13
},
init: function (container) {
this.options.value = container.getAttribute('data-value');
}
};
这是你在记忆中得到的东西(省略了一些细节):
+--------------------+ +------------+ +--->| (Object.prototype) |<-+ original--->| (object) | | +--------------------+ | +------------+ | | | __proto__ |---+ +-------------+ | | options |------->| (object) | | | init |---+ +-------------+ | +------------+ | | __proto__ |---------+ | | value: null | | | factor: 13 | | +-------------+ | | +------------+ +----| (function) | +------------+
...其中__proto__
是一个伪属性,显示对象的原型是什么(具体来说,是spec调用对象的内部[[Proto]]
属性的值)。 (在浏览器上,在ES2015中,实际上有一个__proto__
访问者,但不应该使用它。)
然后当你这样做时:
var variation = Object.create(original);
你有:
+------------+ variation-->| (object) | +------------+ | __proto__ |--+ +------------+ | | +------------------+ +--------------------+ | +->| (Object.prototype) |<-+ \ +------------+ | +--------------------+ | original--->| (object) | | | +------------+ | | | __proto__ |-----+ +-------------+ | | options |------->| (object) | | | init |---+ +-------------+ | +------------+ | | __proto__ |---------+ | | value: null | | | factor: 13 | | +-------------+ | | +------------+ +----| (function) | +------------+
您可以看到original
和variation
仍然指向相同的选项对象。
如果需要单独的选项对象,则必须创建新对象。您可以variation.options
使用original.options
作为原型:
var variation = Object.create(original);
variation.options = Object.create(original.options);
...但是你必须再次 firstDiv
和secondDiv
:
var firstDiv = Object.create(variation);
firstDiv.options = Object.create(variation.options);
var secondDiv = Object.create(variation);
secondDiv.options = Object.create(variation.options);
......这表明我们需要做一些不同的事情。
您可以使用以下功能执行此操作:
function createVariation(source) {
var v = Object.create(source);
v.options = Object.create(source.options);
return v;
}
var variation = createVariation(original);
var firstDiv = createVariation(variation);
var secondDiv = createVariation(variation);
...但您可能会看一下构造函数或制造商函数,以及一个称为“扩展”函数的相当典型的模式(例如jQuery's或Underscore's)。
答案 1 :(得分:1)
firstDiv
和secondDiv
都没有自己的options
属性。两者都从options
继承original
。您可以通过观察下面的所有表达式false
:
variation.hasOwnProperty("options") // false
firstDiv.hasOwnProperty("options") // false
secondDiv.hasOwnProperty("options") // false
您的init
函数执行this.options.value = ...
,但暂时只考虑this.options
这个表达式。您永远不会创建另一个options
对象,因此当您为其firstDiv
对象请求secondDiv
或options
时,会将this.options
查找升级为{{1}原型对象。
因此,当您访问original
或options
的{{1}}属性时,您将导致属性查找升级到firstDiv
(原型中的第一个对象)真正具有secondDiv
属性的链。这意味着original
和options
是完全相同的对象(即firstDiv.options
)。因此,当您设置secondDiv.options
时,您也设置了original.options
。
此处的解决方案是确保secondDiv.options.value
和firstDiv.options.value
明确拥有自己的firstDiv
属性。但是,您还希望secondDiv
值本身继承自options
,并且您希望options
也拥有自己的variation.options
值,该值继承自variation
}。 T.J. Crowder's answer使用options
方法详细说明了这一点:
original.options