Javascript 为什么我在使用同一个缓存对象扩展两个对象时会有一个共享缓存?

Javascript 为什么我在使用同一个缓存对象扩展两个对象时会有一个共享缓存?,javascript,jquery,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

我可以用这个简单的代码片段最好地解释这个问题:

    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?

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

这包括将引用复制到指定给父级的数组中。因此,无论何时从任何对象缓存读取或写入,都会访问相同的数据存储

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

jQuery.extend(true, child1, parent);
jQuery.extend(true, child2, parent);
另一方面,由于您处理的是命名键,所以请使用对象,而不是数组

_cache: {},  // storage var

来自父对象的
\u缓存将复制到两个子对象。因此,本质上,发生了以下情况:

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)
您还可以使用
对象。使用原始代码创建

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

jQuery.extend
与继承无关。它将第二个对象的属性合并到第一个对象。这意味着对
\u缓存的引用既在
child1
中,也在
child2


读取。

您得到结果是因为在您的示例中,
父级
\u缓存
-成员是通过引用复制的。如果查看jQuery的API文档,可以通过将
true
作为第一个参数传递给
jQuery.extend
来强制执行深度复制

在这里查看一个正在工作的JSFIDLE:

这是关于而不是Javascript内置的东西

在本例中,您将使用.extend()使用父对象的属性扩展child2对象

.extend()的jQuery文档有一点提到:

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

这表示父对象的属性被完整复制到child2中。在Javascript中,对象(因此也包括数组)是通过引用复制的_缓存是一个数组,因此当jQuery的extend方法将对象从父对象复制到child2中时,它会复制对现有_缓存数组的引用,而不是复制其所有值,因此最终会引用与父对象相同的数组。对同一数组的引用也被复制到前一行的child1中


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

这似乎是关于jQuery的扩展方法,而不是Javascript继承。太好了,它成功了!谢谢你的详细解释。非常有帮助!谢谢你的回答。但看看昆汀的建议。非常简单的解决方案,无需修改大量代码。@AbhimanyuGrover,没错。我只是不认为使用jquery的extend是一种好的继承模式。在内存使用方面,它当然不比我的原型解决方案好,因为它将这些函数复制到每个孩子身上,而原型没有。