我有一个我正在努力掌握的问题。任何帮助将不胜感激。
我有一个Object,我将当前对象状态分配给当前对象的属性。
以下示例:
var product = {
ropeType: 'blah',
ropePrice: 'blah',
ropeSections: {
name: 'blaah',
price: 'blaah'
},
memory: false
}
product.memory = product;
现在,当我在控制台中查看产品对象时,我得到了Product.memory.Product.memory.Product的无限递归....
截图如下:
我知道它与某个对象引用自身有关,但我似乎无法理解这个概念。有人可以解释一下吗?
我尝试做这样的事情的原因是在本地存储中保存对象的当前状态。
我希望我有道理。
答案 0 :(得分:4)
我将当前对象状态分配给当前对象的属性。
不,你创建了一个自称的属性。
如果要保存属性的当前状态,则需要克隆该对象。
如果要创建对象的(浅)副本,则可以使用:
function clone(obj) {
if(obj === null || typeof(obj) !== 'object' || 'isActiveClone' in obj)
return obj;
var temp = obj.constructor();
for(var key in obj) {
if(Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = obj[key];
delete obj['isActiveClone'];
}
}
return temp;
}
[code taken from here - 并略微修改以执行浅拷贝而不是递归深拷贝]
然后做:
product.memory = clone( product );
如果您再次克隆它,您可能会发现递归问题并将product.memory
与对象的其余部分一起复制。在这种情况下,在进行后续克隆之前只需delete product.memory
。
类似的东西:
function saveCurrentState( obj ){
if ( 'memory' in obj )
delete obj.memory;
obj.memory = clone( obj );
}
<强>除了强>
如果您需要深层复印,则可以执行以下操作:
function deepCopy(obj){
return JSON.parse(JSON.stringify(obj));
}
[As suggested here - 但请注意它对Date对象的注意事项]
答案 1 :(得分:0)
这就是问题所在:
product.memory = product;
您正在为对象分配对象的引用。 JavaScript通过引用传递对象,因此它永远不会通过赋值来存储自身的克隆。
如果您希望记录随时间对对象所做的修改,最好的方法是使用数组来保存它的克隆副本(或者至少保存已更改的属性)。
为您提供最快的例子:
var Product = function(){
};
var product = new Product();
product.history = [];
product.saveState = function(){
var changes = {};
for(var i in this){
/** Prevent infinite self-referencing, and don't store this function itself. */
if(this[i] !== this.history && this[i] !== this.saveState){
changes[i] = this[i];
}
}
this.history.push(changes);
};
显然,有很多更好的方法可以在JavaScript中实现这一点,但它们需要更多解释。基本上,循环遍历一个对象来存储它的属性不可避免地会绊倒它们被分配给它的属性,因此需要在某些时候进行检查以防止自我引用。
答案 2 :(得分:0)
您可以通过将当前产品克隆为新产品来实现您的想法。我们Object.keys
获取对象的所有属性。所以这是我的想法:
product = {
ropeType: 'blah',
ropePrice: 'blah',
ropeSections: {
name: 'blaah',
price: 'blaah'
},
memory: false
};
var keys = Object.keys(product);
var newProduct = {};
keys.forEach(function(key){
if(key === 'memory') return;
newProduct[key] = product[key];
});
product.memory = newProduct;
答案 3 :(得分:0)
您可能希望转换该对象的状态,而不是实际存储对象的引用。也许通过将其克隆到一个新对象上或者可能将其保存为JSON字符串(如果您正在使用localStorage
,那么您将要执行此操作)。
由于您可能希望在检查memory
属性时看到对象的当前状态,因此您应该使memory
成为执行该转换的函数。 / p>
也许是这样的:
var product = {
ropeType: 'blah',
ropePrice: 'blah',
ropeSections: {
name: 'blaah',
price: 'blaah'
},
memory: function() {
return JSON.stringify(this);
}
}
然后,您可以调用product.memory()
并以JSON格式获取其状态。