Javascript Object Assignment Infinite recursion

◇◆丶佛笑我妖孽 提交于 2021-02-08 03:33:06

问题


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:

enter image description here

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!