简体   繁体   English

在JavaScript中删除对象时的奇怪行为

[英]Strange behavior when deleting object in JavaScript

I am facing some strange behavior when I try to delete an object from an array. 当我尝试从数组中删除对象时,我面临一些奇怪的行为。

Please have a look at code. 请看一下代码。 I am using recursive function. 我正在使用递归函数。

 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) 

In first function, it doesn't delete the object with id="236448654". 在第一个功能中,它不会删除id =“ 236448654”的对象。

In second function, it deletes the object. 在第二个功能中,它删除对象。 In both function code is same but just delete statement has different location. 在这两个函数中代码是相同的,但只是delete语句具有不同的位置。

Can any one please explain me this behavior ? 有人能解释一下这种行为吗?

Thank you. 谢谢。

Talking about the issue in you code, first I have to say that using delete is not quite good since it's has negative effects for the V8 classes 谈到您的代码中的问题,首先我不得不说使用delete并不是很好,因为它对V8类有负面影响

Here's a sample example how delete works : 以下是删除操作的示例示例:

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

As you see it require the key of the object that will be deleted with is not the case for you since your object is has no keys 如您所见,由于您的对象没有密钥,因此您不需要使用将被删除的对象的密钥

For this I had to edit your object from array of objects to objects of objects since I cant set the keys inside the array so that we can use the delete operator, I had also to delete the deleteNodeFromArray function since it has no use anymore without an array. 为此,我无法将对象从对象数组编辑为对象对象,因为我无法在数组中设置键,以便我们可以使用delete运算符,我还必须删除deleteNodeFromArray函数,因为如果没有数组。

Here's your solution with the necessary corrections and optimizations : 这是您的解决方案,其中包含必要的更正和优化:

 // 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) 

And this is my old (working) solution from the first edit is which I used the filter function so I can generate new object that satisfy my needs: 这是我第一次编辑时使用的旧的(有效的)解决方案,它使用了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")); 

pure recursion 纯递归

delete is very misunderstood, but because it produces a side effect (imperative style), using it with recursion (function style) causes a bit of a clash. delete是一个很容易被误解的方法,但是由于它会产生副作用(命令式),因此将其与递归一起使用(函数式)会引起一些冲突。

If you write a pure function, the original data is not mutated, and instead the "next" state of the data is returned. 如果编写函数,则原始数据不会发生突变,而是返回数据的“下一个”状态。 The primary advantage here is that you don't have to concern yourself with side effects. 这里的主要优点是您不必担心副作用。 This naturally encourages a recursive pattern where a node's children are the result of the removeNode called on each child. 这自然会鼓励一种递归模式,其中节点的子代是在每个子代上调用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)
      }

Here's a full working demo 这是一个完整的工作演示

 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)) 

It's about garbage collector. 关于垃圾收集器。 You cannot remove any object in JS, all what you can - it is remove reference to object at some place. 您无法全部删除JS中的任何对象-它是在某个位置删除对对象的引用。 When you invoke delete bigObjectToSearch; 调用delete bigObjectToSearch; or delete bigObjectToSearch.children[i]; delete bigObjectToSearch.children[i]; it don't delete object, it try to delete reference to that object - and don't touch object itself. 它不删除对象,而是尝试删除对该对象的引用-并且不要触摸对象本身。

Also, in first function (here delete bigObjectToSearch; ) you tried to delete entire object, while 'delete' work only with object properties, so you just can't 另外,在第一个函数(此处为delete bigObjectToSearch; )中,您试图删除整个对象,而“删除”仅适用于对象属性,因此您不能

In second function you successfully removed object property, which in fact not object itself, just link to them. 在第二个函数中,您成功删除了对象属性,实际上不是对象本身,而是链接到它们。 So, in fact "deleted" object still exists. 因此,实际上“已删除”对象仍然存在。 And it will exist until some link to them exists, and if no - it would be garbage collected at some moment. 它会一直存在,直到与它们的某些链接存在为止;如果不存在,则此刻将被垃圾回收。

In JS you cannot force delete any object, you must to control all referenced to do not create memory leaks. 在JS中,您不能强制删除任何对象,必须控制所有引用的对象,以免造成内存泄漏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM