问题
I have an issue that I am struggling to grasp. Any help would be greatly appreciated.
I have an Object, and I assign the current object state to a property on the current object.
example below:
var product = {
ropeType: 'blah',
ropePrice: 'blah',
ropeSections: {
name: 'blaah',
price: 'blaah'
},
memory: false
}
product.memory = product;
Now when I look at the product object within the console I get a inifinite recursion of Product.memory.Product.memory.Product....
screenshot below:
I know its something to do with that an object references itself, but I cannot seem to grasp the concept. Could someone explain?
The reason I am trying to do something like this is to save in local storage the current state of the object.
I hope I have made sense.
回答1:
I assign the current object state to a property on the current object.
No, you created a property that referred to itself.
If you want to save the current state of the property then you need to clone the object.
If you want to create a (shallow) copy of an object then you can use:
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 - and modified slightly to do a shallow copy rather than recursive deep copy]
then do:
product.memory = clone( product );
You may find you get the issues with recursion if you clone it a second time and it copies the product.memory
along with the rest of the object. In that case just delete product.memory
before doing subsequent clones.
Something like:
function saveCurrentState( obj ){
if ( 'memory' in obj )
delete obj.memory;
obj.memory = clone( obj );
}
Aside
If you want a deep copy then you can do:
function deepCopy(obj){
return JSON.parse(JSON.stringify(obj));
}
[As suggested here - but note the caveats it has for Date objects]
回答2:
you could do your idea by clone the current product into new. We've Object.keys
to get all attribute of object. So here is my idea :
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:
Instead of actually storing a reference to the object, you might want to transform that object's state. Maybe by cloning it onto a new object or possibly keeping it as a JSON string (which you'll want to do if you're using localStorage
).
Since you will probably want to see the current state of the object whenever you check the memory
property, you should make memory
a function that does that transformation.
Maybe something like this:
var product = {
ropeType: 'blah',
ropePrice: 'blah',
ropeSections: {
name: 'blaah',
price: 'blaah'
},
memory: function() {
return JSON.stringify(this);
}
}
You can then call product.memory()
and get its state in JSON.
回答4:
This here is the problem:
product.memory = product;
You're assigning a reference to an object to itself. JavaScript passes objects by reference, so it's never going to store a clone of itself through assignment.
If you're looking to record modifications made to the object over time, the best way would be to use an array to hold cloned copies of it (or at least the properties that've changed).
To give you the quickest example:
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);
};
Obviously, there're many better ways to achieve this in JavaScript, but they require more explanation. Basically, looping through an object to store its properties is inevitably going to trip up upon the property that they're being assigned to, so a check is needed at some point to prevent self-referencing.
来源:https://stackoverflow.com/questions/31061708/javascript-object-assignment-infinite-recursion