为什么我有一个共享缓存时,我jQuery.使用相同的缓存对象扩展两个对象
Why do I have a shared cache when I `jQuery.extend` two objects with the same caching object?
我可以用这个简单的代码片段最好地解释这个问题:
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'));
现在为什么它返回123当我们只访问了child1的writeCache()?
jQuery的extend方法复制第二个对象中的所有内容,并将其放在第一个对象中。
这包括将引用复制到分配给parent._cache
的数组。因此,无论何时从任何对象缓存中读取或写入,都要访问相同的数据存储。
要避免这种情况,请进行深拷贝。
jQuery.extend(true, child1, parent);
jQuery.extend(true, child2, parent);
作为题外话,因为您处理的是命名键,所以请使用Object,而不是Array。
_cache: {}, // storage var
jQuery.extend
与继承无关。它将第二个对象的属性与第一个对象合并。这意味着对_cache
的引用同时位于child1
和child2
中。
阅读http://api.jquery.com/jQuery.extend/。
您得到的结果是因为在您的示例中parent
的_cache
-成员是通过引用复制的。如果你看一下jQuery的api文档,你可以通过将true
作为第一个参数传递给jQuery.extend
来强制深度复制。
在这里看到一个工作的jsFiddle: http://jsfiddle.net/mLfUE/
将parent
中的_cache
复制到两个子对象。基本上,会发生以下情况:
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:[] }} )
这是关于jQuery的扩展方法,而不是Javascript内置的东西。
在本例中,您使用.extend()用父对象的属性扩展child2对象。
.extend()的jQuery文档中有一点提到:
$.extend()执行的合并在默认情况下不是递归的;
表示将parent的属性全部复制到child2中。在Javascript中,对象(也包括数组)是通过引用复制的。_cache是一个数组,所以当jQuery的extend方法将对象从parent复制到child2时,它会复制对现有_cache数组的引用,而不是复制它的所有值,所以它最终会引用与parent相同的数组。对同一数组的引用也被复制到前一行的child1中。
当通过引用复制时,引用继续指向同一个对象,使用它的任何一个引用修改该对象都会影响原始对象。
- 强制浏览器更新缓存的HTML5视频对象
- 如何创建jQuery插件来缓存jQuery对象,如下所示
- Ace代码编辑器:缓存模式对象
- Js对象缓存性能
- 在Angularjs服务中为返回对象引用的http请求提供的数据构建简单的缓存
- 检查对象是否适合浏览器缓存
- 如何在 Firefox 中查找特定的缓存条目并将它们转换为文件或 Blob 对象
- JavaScript 缓存对象与压缩
- 问题:在传递给函数时缓存 jquery 对象
- JQuery 方法不适用于缓存的子对象
- 在缓存对象文字中的元素时使用find()的语法
- Nodejs使用回调函数缓存有状态对象
- jquery ui的客户端缓存自动完成:javascript/jquery regex匹配字符串"索引“;对象
- 在浏览器中缓存对象时,内存过多
- 如何缓存ajax json对象以在图表中使用
- 缓存一个“;深“;使用GUID作为键的JSON对象
- jQuery;IE7+缓存的$对象出现意外行为
- 使用jQuery缓存对象中的选择器
- 如何构建一个虚拟对象缓存
- AngularJS将对象缓存设置为dirty