2015-06-25 62 views
1

我有一個問題,我正在努力抓住。任何幫助將不勝感激。Javascript對象賦值無限遞歸

我有一個對象,我將當前對象狀態分配給當前對象的屬性。下面

例如:

var product = { 
    ropeType: 'blah', 
    ropePrice: 'blah', 
    ropeSections: { 
    name: 'blaah', 
    price: 'blaah' 
    }, 
    memory: false 
} 

product.memory = product; 

現在,當我看到控制檯我得到Product.memory.Product.memory.Product的inifinite遞歸內的產品對象....下面

截圖:

enter image description here

我知道它是與一個對象引用自身,但我似乎無法把握的概念。有人可以解釋嗎?

我試圖做這樣的事情的原因是保存在本地存儲當前狀態的對象。

我希望我有道理。

+0

究竟是什麼,你不明白?這是一個循環數據結構。考慮一個循環路徑。如果沿着小徑漫步,你最終會走到你開始的地方。 –

+0

使用其他變量來存儲對象。如果你將一個對象附加到它自己的一個屬性上,它將會是無限的自我引用。 –

+0

好的,所以對象總是自引用? – Adamski

回答

3

我將當前對象狀態分配給當前對象的屬性。

不,你創建了一個稱爲本身的屬性。

如果你想救樓市的當前狀態,那麼你需要克隆的對象。

如果你想創建一個對象的(淺)的副本,那麼你可以使用:

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 - 但請注意它有日期的注意事項物件]

+0

我將如何實現使用ES5? – Adamski

+0

檢查我的:) @Adamski – Kai

+0

淺淺之間有什麼區別? – Adamski

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中實現這一點,但他們需要更多的解釋。基本上,循環一個對象來存儲它的屬性不可避免地會被分配到它的屬性上,所以需要在某些時候檢查以防止自引用。

+0

好的,謝謝,你會如何實現我想要做的? – Adamski

+0

我會更新我的答案,給我一點時間。 – Alhadis

+0

完成。請記住,這不是最好的解決方案,但如果您還不熟悉JavaScript中屬性分配和引用的工作方式,那麼這可能是最容易解釋的。 – Alhadis

0

you co通過將當前產品克隆到新產品中來實現您的想法。我們有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; 
+1

[Object.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys#Browser_compatibility)不支持所有瀏覽器 - 即IE8及更早版本以及其他老版本的瀏覽器。 – MT0

+0

他只要求ES5,所以我認爲它會工作得很好:)。 – Kai

0

而不是實際存儲的對象的引用,你可能想變換該對象的狀態。也許把它克隆到一個新的對象上,或者把它保存爲一個JSON字符串(如果你使用的是localStorage,你會這樣做)。

既然你可能會想看清物體的當前狀態時,你檢查memory屬性,你應該memory,做這一轉變的功能。

也許是這樣的:

var product = { 
    ropeType: 'blah', 
    ropePrice: 'blah', 
    ropeSections: { 
    name: 'blaah', 
    price: 'blaah' 
    }, 
    memory: function() {  
    return JSON.stringify(this); 
    } 
} 

你可以調用product.memory()和JSON獲取其狀態。