最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

oop - Javascript Object Assignment Infinite recursion - Stack Overflow

programmeradmin1浏览0评论

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.

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.

Share Improve this question edited Jun 25, 2015 at 22:21 Felix Kling 817k181 gold badges1.1k silver badges1.2k bronze badges asked Jun 25, 2015 at 22:13 AdamskiAdamski 8992 gold badges10 silver badges28 bronze badges 4
  • What exactly is it that you don't understand? It's a cyclic data structure. Think about a circular path. If walk along the path you eventually end up where you started. – Felix Kling Commented Jun 25, 2015 at 22:16
  • Use a different variable to store the object. If you attach an object to a property of itself, it's going to be infinitely self-referential. – Michael Todd Commented Jun 25, 2015 at 22:17
  • Oh ok, so objects are always self referencing? – Adamski Commented Jun 25, 2015 at 22:21
  • Uhm, no. But objects are represented through references. product.memory = product; assigns a reference to product to itself. – Felix Kling Commented Jun 25, 2015 at 22:22
Add a ment  | 

5 Answers 5

Reset to default 4

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]

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;

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.

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.

I had same issue, I solved it by just using the spread operator, like:

product = {...product, memory: product}
发布评论

评论列表(0)

  1. 暂无评论