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

时间:2018-01-24 10:28:22

标签: javascript 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'
    }]
};

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”的对象。

在第二个函数中,它删除对象。两个功能代码都相同但是 只是删除语句有不同的位置。

任何人都可以解释一下这种行为吗?

谢谢。

3 个答案:

答案 0 :(得分:1)

在谈论代码中的问题时,首先我要说使用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)

这是我从第一次编辑的旧(工作)解决方案,我使用了过滤器功能,因此我可以生成满足我需求的新对象:

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

答案 1 :(得分:1)

纯递归

delete被误解,但因为它会产生副作用(命令式),使用递归(函数样式)会导致一些冲突。

如果您编写函数,原始数据不会发生变异,而是#34; next&#34;返回数据的状态。这里的主要优点是你不必担心副作用。这自然会鼓励一种递归模式,其中节点的子节点是每个孩子调用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)
      }

这是一个完整的演示

&#13;
&#13;
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))
&#13;
&#13;
&#13;

答案 2 :(得分:0)

关于垃圾收集器。您不能删除JS中的任何对象,所有这些都可以 - 它是在某个地方删除对象的引用。当您调用delete bigObjectToSearch;delete bigObjectToSearch.children[i];时,它不会删除对象,它会尝试删除对该对象的引用 - 并且不要触摸对象本身。

此外,在第一个函数(此处为delete bigObjectToSearch;)中,您尝试删除整个对象,而“删除”仅使用对象属性,因此您无法

在第二个函数中,您成功删除了对象属性,实际上它不是对象本身,只是链接到它们。所以,实际上“删除”对象仍然存在。它会存在,直到它们存在一些链接,如果没有 - 它会在某个时刻被垃圾收集。

在JS中你不能强制删除任何对象,你必须控制所有引用的不要创建内存泄漏。