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是一种好的继承模式。在内存使用方面,它当然不比我的原型解决方案好,因为它将这些函数复制到每个孩子身上,而原型没有。