对象包含相同的值,但不应该

2022-03-14 00:00:00 javascript javascript-objects

我尝试实现对象继承,其中每个对象共享相同的功能,但包含不同的值/容器。这样做时,我发现了一种奇怪的行为;每个单独的对象都像符咒一样工作,但它们都有相同的选项。请务必澄清我的意思,我添加了示例代码。

我要做的是从每个元素读取数据值,并将其绑定到选项。某些函数需要这些才能正常工作!

<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()的。


解决方案

对象包含相同的值,但不应该

应该如此,因为您没有更改variation上的options属性,所以它仍然指向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__是显示对象原型的伪属性(具体地说,规范称为对象的内部[[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) |
                                  +−−−−−−−−−−−−+

您可以看到originalvariation仍然指向相同的选项对象。

如果您想要单独的选项对象,则必须创建一个新对象。您可以使variation.options使用original.options作为其原型:

var variation = Object.create(original);
variation.options = Object.create(original.options);

.但之后您必须为firstDivsecondDiv重新:

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)。

相关文章