当我在`jQuery.extend`两个具有相同缓存对象的对象时,为什么我有一个共享缓存?

时间:2011-10-09 08:12:32

标签: javascript jquery

我可以通过这个简单的代码片段来解释这个问题:

    var child1 = {name: 'child1'};
    var child2 = {name: 'child2'};

    var parent = {
        _cache: [],  // storage var
        writeCache: function(key, val)
        {
            console.log('writing cache::'+this.name);
            this._cache[key] = val;
        },
        readCache: function(key)
        {
            if(this._cache[key] == undefined)
            {
                return false;
            }
            return this._cache[key];
        },
    };
    jQuery.extend(child1, parent);
    jQuery.extend(child2, parent);

    child1.writeCache('myKey', 123);

    console.log(child1.readCache('myKey'));  // returns 123 as expected

    console.log(child2.readCache('myKey'));  // returns 123 unexpectedly (for me at least)

见最后一行:

    console.log(child2.readCache('myKey'));

现在为什么当我们只访问child1的writeCache()?

时它会返回123

5 个答案:

答案 0 :(得分:4)

jQuery的extend方法复制第二个对象中的所有内容并将其放在第一个对象中。

包括将引用复制到您分配给parent._cache的数组。因此,无论何时从任何对象缓存中读取或写入,都可以访问同一个数据存储。

要避免这种情况,请进行深层复制。

jQuery.extend(true, child1, parent);
jQuery.extend(true, child2, parent);

顺便说一句,由于您正在处理命名键,因此请使用Object,而不是Array。

_cache: {},  // storage var

答案 1 :(得分:1)

_cache中的parent被复制到两个子对象。基本上,会发生以下情况:

child1._cache = parent._cache
child2._cache = parent._cache

但现在他们都在内存中引用相同的数组(js传递相同的引用)。因此,当你改变它时,你应该期望它反映在别处。例如:

parent = {_cache:[]}
child1 = {}
child2 = {}

child1._cache = parent._cache
child2._cache = parent._cache

child1._cache.push(9)
child2._cache; // [9]

您可以使用原型继承解决此问题:

function parent(){
   this._cache = [];
}
parent.prototype.writeCache = ...
parent.prototype.readCache = ...

child1 = new parent();
child2 = new parent();

child1.writeCache('myKey', 123);

console.log(child1.readCache('myKey')); // 123
console.log(child2.readCache('myKey')); // undefined (/false in your case)

您还可以将Object.create与原始代码一起使用:

child1 = Object.create(parent, {_cache: { value:[] }} )
child2 = Object.create(parent, {_cache: { value:[] }} )

答案 2 :(得分:1)

jQuery.extend与继承无关。它将第二个对象的属性合并到第一个对象。这意味着您_cache的引用位于child1child2

阅读http://api.jquery.com/jQuery.extend/

答案 3 :(得分:1)

您得到了结果,因为_cache - parent成员在您的示例中通过引用复制。如果您查看jQuery的API-docs,可以通过将true作为第一个参数传递给jQuery.extend来强制执行深层复制。

在此处查看有效的jsFiddle:http://jsfiddle.net/mLfUE/

答案 4 :(得分:0)

这大约是jQuery's extend method,而不是内置于Javascript中的内容。

在这种情况下,您使用.extend()来扩展带有父对象属性的child2对象。

.extend()的jQuery文档在某一点上提到:

  

默认情况下,$ .extend()执行的合并不是递归的;

这表明父元素的属性被整体复制到child2中。在Javascript中,对象(以及因此也是数组)通过引用复制。 _cache是​​一个数组,所以当jQuery的extend方法是将对象从parent复制到child2时,它会复制对现有_cache Array的引用,而不是复制其所有值,因此它最终会引用与父对象相同的数组。对同一数组的引用也被复制到前一行中的child1中。

通过引用复制时,引用继续指向同一个对象,并使用其任何一个引用修改该对象将影响原始对象。