簡體   English   中英

在JavaScript中刪除對象時的奇怪行為

[英]Strange behavior when deleting object in JavaScript

當我嘗試從數組中刪除對象時,我面臨一些奇怪的行為。

請看一下代碼。 我正在使用遞歸函數。

 var obj = { 'id': '234567869', 'name': 'Lao Lao', 'title': 'general manager', 'children': [{ 'id': '467876756634', 'name': 'Bo Miao', 'title': 'department manager' }, { 'id': '2345666078', 'name': 'Su Miao', 'title': 'department manager', 'children': [{ 'id': '898735342', 'name': 'Tie Hua', 'title': 'senior engineer' }, { 'id': '7697347548', 'name': 'Hei Hei', 'title': 'senior engineer', 'children': [{ 'id': '123415640', 'name': 'Pang Pang', 'title': 'engineer' }, { 'id': '1237450976', 'name': 'Xiang Xiang', 'title': 'UE engineer' }] }] }, { 'id': '6968756535', 'name': 'Yu Jie', 'title': 'department manager' }, { 'id': '236448654', 'name': 'Chun Miao', 'title': 'department manager' }, { 'id': '356898765', 'name': 'Yu Tie', 'title': 'department manager' }] }; function deleteNode(idToFind, bigObjectToSearch) { var i, currentChild, result; if (idToFind == bigObjectToSearch.id) { //I try to delete the object here but can't :( delete bigObjectToSearch; return true; } else if (bigObjectToSearch.children) { for (i = 0; i < bigObjectToSearch.children.length; i += 1) { currentChild = bigObjectToSearch.children[i]; // Search in the current child if(deleteNode(idToFind, currentChild)){ break; }; } return false; } return false; } deleteNode('236448654', obj); console.log(obj); function deleteNodeFromArray(idToFind, bigObjectToSearch) { var i, currentChild, result; if (idToFind == bigObjectToSearch.id) { //I try to delete the object here but can't :( //delete bigObjectToSearch; return true; } else if (bigObjectToSearch.children) { for (i = 0; i < bigObjectToSearch.children.length; i += 1) { currentChild = bigObjectToSearch.children[i]; // Search in the current child if(deleteNodeFromArray(idToFind, currentChild)){ //If I delete from here, it works. delete bigObjectToSearch.children[i]; break; }; } return false; } return false; } deleteNodeFromArray('236448654', obj); console.log(obj) 

在第一個功能中,它不會刪除id =“ 236448654”的對象。

在第二個功能中,它刪除對象。 在這兩個函數中代碼是相同的,但只是delete語句具有不同的位置。

有人能解釋一下這種行為嗎?

謝謝。

談到您的代碼中的問題,首先我不得不說使用delete並不是很好,因為它對V8類有負面影響

以下是刪除操作的示例示例:

 // var keyToDelete = "key1"; var myObj = { "test": { "key1": "value", "key2": "value" } } delete myObj.test[keyToDelete]; console.log(myObj) 

如您所見,由於您的對象沒有密鑰,因此您不需要使用將被刪除的對象的密鑰

為此,我無法將對象從對象數組編輯為對象對象,因為我無法在數組中設置鍵,以便我們可以使用delete運算符,我還必須刪除deleteNodeFromArray函數,因為如果沒有數組。

這是您的解決方案,其中包含必要的更正和優化:

 // var obj = { "234567869": { 'id': '234567869', 'name': 'Lao Lao', 'title': 'general manager', 'children': { "467876756634": { 'id': '467876756634', 'name': 'Bo Miao', 'title': 'department manager' }, "2345666078": { 'id': '2345666078', 'name': 'Su Miao', 'title': 'department manager', 'children': { "898735342": { 'id': '898735342', 'name': 'Tie Hua', 'title': 'senior engineer' }, "7697347548": { 'id': '7697347548', 'name': 'Hei Hei', 'title': 'senior engineer', 'children': { "123415640": { 'id': '123415640', 'name': 'Pang Pang', 'title': 'engineer' }, "1237450976": { 'id': '1237450976', 'name': 'Xiang Xiang', 'title': 'UE engineer' } } } } }, "6968756535": { 'id': '6968756535', 'name': 'Yu Jie', 'title': 'department manager' }, "236448654": { 'id': '236448654', 'name': 'Chun Miao', 'title': 'department manager' }, "356898765": { 'id': '356898765', 'name': 'Yu Tie', 'title': 'department manager' } } } }; function deleteNode(idToFind, bigObjectToSearch) { var i, currentChild, result; for (var key in bigObjectToSearch) { if (idToFind == bigObjectToSearch[key].id) { delete bigObjectToSearch[key]; } else if (bigObjectToSearch[key].children) { deleteNode(idToFind, bigObjectToSearch[key].children) } } } deleteNode('7697347548', obj); console.log(obj) 

這是我第一次編輯時使用的舊的(有效的)解決方案,它使用了filter函數,因此我可以生成滿足我的需求的新對象:

 //i changed the type of obj to array to it will be more easier to run the recursion var obj = [{ 'id': '234567869', 'name': 'Lao Lao', 'title': 'general manager', 'children': [{ 'id': '467876756634', 'name': 'Bo Miao', 'title': 'department manager' }, { 'id': '2345666078', 'name': 'Su Miao', 'title': 'department manager', 'children': [{ 'id': '898735342', 'name': 'Tie Hua', 'title': 'senior engineer' }, { 'id': '7697347548', 'name': 'Hei Hei', 'title': 'senior engineer', 'children': [{ 'id': '123415640', 'name': 'Pang Pang', 'title': 'engineer' }, { 'id': '1237450976', 'name': 'Xiang Xiang', 'title': 'UE engineer' }] }] }, { 'id': '6968756535', 'name': 'Yu Jie', 'title': 'department manager' }, { 'id': '236448654', 'name': 'Chun Miao', 'title': 'department manager' }, { 'id': '356898765', 'name': 'Yu Tie', 'title': 'department manager' }] }]; // the recursive funtion that will call itself function looperRec(obj, id) { //delete the object that has the passed id from the array var obj = obj.filter(function(item) { return item.id !== id; }); //loop the array in order to find the children for (i in obj) { // if children exist call the function again if (obj[i].hasOwnProperty('children')) { //replace the old data with the new one only when the attribute children exist obj[i].children = looperRec(obj[i].children, id) } } //return the result of each step in the recursion return obj; } //display the result console.log(looperRec(obj, "898735342")); 

純遞歸

delete是一個很容易被誤解的方法,但是由於它會產生副作用(命令式),因此將其與遞歸一起使用(函數式)會引起一些沖突。

如果編寫函數,則原始數據不會發生突變,而是返回數據的“下一個”狀態。 這里的主要優點是您不必擔心副作用。 這自然會鼓勵一種遞歸模式,其中節點的子代是在每個子代上調用removeNode的結果。

const identity = x =>
  x

const removeNode = (match, { id, name, title, children = [] }) =>
  match === id
    ? null
    : { id : id
      , name : name
      , title : title
      , children : children.map (n => removeNode (match, n)) .filter (identity)
      }

這是一個完整的工作演示

 const identity = x => x const removeNode = (match, { id, name, title, children = [] }) => match === id ? null : { id : id , name : name , title : title , children : children.map (n => removeNode (match, n)) .filter (identity) } const node = { id : "234567869" , name : "Lao Lao" , title : "general manager" , children : [ { id : "467876756634" , name : "Bo Miao" , title : "department manager" } , { id : "2345666078" , name : "Su Miao" , title : "department manager" , children : [ { id : "898735342" , name : "Tie Hua" , title : "senior engineer" } , { id : "7697347548" , name : "Hei Hei" , title : "senior engineer" , children : [ { id : "123415640" , name : "Pang Pang" , title : "engineer" } , { id : "1237450976" , name : "Xiang Xiang" , title : "UE engineer" } ] } ] } , { id : "6968756535" , name : "Yu Jie" , title : "department manager" } , { id : "236448654" , name : "Chun Miao" , title : "department manager" } , { id : "356898765" , name : "Yu Tie" , title : "department manager" } ] } console.log (removeNode ("236448654", node)) 

關於垃圾收集器。 您無法全部刪除JS中的任何對象-它是在某個位置刪除對對象的引用。 調用delete bigObjectToSearch; delete bigObjectToSearch.children[i]; 它不刪除對象,而是嘗試刪除對該對象的引用-並且不要觸摸對象本身。

另外,在第一個函數(此處為delete bigObjectToSearch; )中,您試圖刪除整個對象,而“刪除”僅適用於對象屬性,因此您不能

在第二個函數中,您成功刪除了對象屬性,實際上不是對象本身,而是鏈接到它們。 因此,實際上“已刪除”對象仍然存在。 它會一直存在,直到與它們的某些鏈接存在為止;如果不存在,則此刻將被垃圾回收。

在JS中,您不能強制刪除任何對象,必須控制所有引用的對象,以免造成內存泄漏。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM