如何从JavaScript对象中移除一个属性?

说我创build一个对象如下:

var myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; 

如何删除属性regex以最终的新myObject的最佳方式是什么?

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI" }; 

喜欢这个:

 delete myObject.regex; // or, delete myObject['regex']; // or, var prop = "regex"; delete myObject[prop]; 

演示

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; delete myObject.regex; console.log(myObject); 

操作员delete出乎意料地慢!

基准

删除是唯一真正的方法来删除对象的属性没有任何残羹剩饭,但它的工作〜100倍慢 ,相比,“替代”,设置object[key] = undefined

这个select不是这个问题的正确答案! 但是,如果你小心使用它,你可以大大加快一些algorithm。 如果在循环中使用delete ,并且在性能方面存在问题,请阅读详细的解释。

何时应该使用delete ,何时将值设置为undefined

一个对象可能被看作是一组键值对。 我称之为“价值”是一个原始的或对其他对象的引用,连接到“钥匙”。

当你将结果对象传递给你没有控制权的代码时(或者当你不确定你的团队或你自己的时候) ,使用delete

从哈希映射中删除密钥

  var obj = { field: 1 }; delete obj.field; 

当您关心性能时,使用设置为undefined 。 它可以大大提高你的代码。

关键在于它在hashmap中的位置 ,只有值被undefined取代。 明白, for..in循环仍然会迭代该键。

  var obj = { field: 1 }; obj.field = undefined; 

使用这种方法,并不是所有确定财产存在的方法都能按预期工作。

但是,这个代码:

object.field === undefined

对于这两种方法将performance等同。

testing

总而言之,不同之处在于确定财产存在的方式,以及关于…在循环中的方式。

  console.log('* -> "Takes prototype inheritance into consideration, that means it lookups all over prototype chain too."'); console.log(obj.field === undefined, 'obj.field === undefined', 'You get "undefined" value when querying for "field" in object-hashmap. *'); console.log(obj["field"] === undefined, 'obj["field"] === undefined', 'Just another way to query (equivalent). *'); console.log(typeof obj.field === "undefined", 'typeof obj.field === "undefined"', 'Get the value attached to "field" key, and check it\'s type is "undefined". *'); console.log("field" in obj, '"field" in obj', 'This statement returns true if "field" key exists in the hashmap. False otherwise. *'); console.log(obj.hasOwnProperty("field"), 'obj.hasOwnProperty("field")', 'This statement returns true if \'field\' key exists in the hashmap. The ONLY way NOT to lookup for property in the prototype chain!'); //Object.keys().indexOf() is an overkill :) var counter = 0, key; for (key in obj) { counter++; } console.assert(counter === 0, 'counter === 0', '"field" is not iterated using "for .. in" loop. *'); 
 var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; delete myJSONObject.regex; console.log ( myJSONObject.regex); // alerts: undefined 

正如其他人所说,你可以使用delete 。 但是JavaScript是一种OOP语言,所以一切都是一个对象。 因此,我觉得有必要指出一个特别的警告。

在数组中,与普通的旧对象不同,使用delete留下nullforms的垃圾,在数组中创build一个“空洞”。

 var array = [1, 2, 3, 4]; delete array[2]; /* Expected result --> [1, 2, 4] * Actual result --> [1, 2, null, 4] */ 

正如你所看到的, delete并不总是像人们所期望的那样工作。 该值被覆盖,但内存不重新分配。

忽略null固有的危险和问题以及浪费的空间,如果arrays需要精确的话,这可能是有问题的。

例如,假设您正在创build一个使用JSON序列化的Web应用程序来将用于“选项卡”的数组存储在string中(在本例中为localStorage )。 我们还要说,代码使用数组成员的数字索引在画到屏幕时“标题”。 你为什么这样做,而不是只存储“标题”? 因为… 原因

好吧,我们只是说,你正在试图在1960年代运行UNIX的PDP-11小型计算机的用户请求下节省内存,并且写了他自己的基于Elinks的JavaScript兼容的行式打印机友好型浏览器,因为X11是不可能

抛开边缘情况越来越愚蠢,在数组上使用delete操作将导致null污染数组,并可能在后来导致应用程序中的错误。 如果您检查为null ,它会直接跳过数字导致制表符像[1] [2] [4] [5] ...

 if (array[index] == null) continue; else title = (index + 1).toString(); /* 0 -> "1" * 1 -> "2" * 2 -> (nothing) * 3 -> "4" */ 

是的,这绝对不是你想要的。

现在,你可以保留第二个迭代器,比如j ,只有在从数组中读取有效值时才会增加。 但是这并不能完全解决null问题,你还是得请那个troll PDP-11用户。 唉,他的电脑只是没有足够的内存来保存最后一个整数(不要问他如何处理可变宽度的数组…)

所以,他愤怒地发给你一封电子邮件:

 Hey, your webapp broke my browser! I checked my localStorage database after your stupid code made my browser segfault, and this is what I found: >"tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... ]" After clearing my precious data, it segfaulted again, and I did a backtrace, and what do I find? WHAT DO I FIND!? YOU USE TOO MANY VARIABLES! >var i = index; >var j = 1; Grr, I am angry now. -Troll Davidson 

大约现在,你在智慧的结尾。 这家伙一直在不停地抱怨你的应用程序,你想告诉他闭嘴,去找一台更好的电脑。

幸运的是,数组确实有删除索​​引和重新分配内存的特殊方法: Array.prototype.splice() 。 你可以写这样的东西:

 Array.prototype.remove = function(index){ this.splice(index,1); } ... array = [1, 2, 3, 4]; array.remove(2); // Result -> [1, 2, 4] 

就这样,你很高兴PDP-11先生。 万岁! (虽然…我仍然告诉他)

另一种select是使用Underscore.js库。

请注意_.pick()_.omit()都返回对象的副本,不直接修改原始对象。 将结果分配给原始对象应该这样做(未显示)。

参考: link _.pick(object,* keys)

返回该对象的副本,过滤为只有白名单键(或有效键数组)的值。

 var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; _.pick(myJSONObject, "ircEvent", "method"); => {"ircEvent": "PRIVMSG", "method": "newURI"}; 

引用: link _.omit(object,* keys)

返回对象的副本,过滤以省略黑名单键(或键列)。

 var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; _.omit(myJSONObject, "regex"); => {"ircEvent": "PRIVMSG", "method": "newURI"}; 

对于数组,可以以类似的方式使用_.filter()_.reject()

老问题,现代答案。 使用对象解构, ECMAScript 6function,就像下面这样简单:

 const { a, ...rest } = { a: 1, b: 2, c: 3 }; 

或者与问题示例:

 const myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; const { regex, ...newObject } = myObject; console.log(newObject); 

你可以在Babel试用编辑器中看到它的行动。


编辑:

要重新分配到相同的variables,请使用let

 let myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; ({ regex, ...myObject } = myObject); console.log(myObject); 

您在问题标题中使用的术语Remove a property from a JavaScript object ,可以用某种不同的方式解释。 一个是删除它的整个内存和对象键列表或另一个只是将其从您的对象中删除。 正如其他答案中提到的, delete关键字是主要部分。 假设你有这样的对象:

 myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; 

如果你这样做:

 console.log(Object.keys(myJSONObject)); 

结果将是:

 ["ircEvent", "method", "regex"] 

您可以从对象键中删除特定的键,如:

 delete myJSONObject["regex"]; 

然后你的对象键使用Object.keys(myJSONObject)将是:

 ["ircEvent", "method"] 

但重点是如果您关心内存,并且希望整个对象从内存中移除,build议在删除键之前将其设置为null:

 myJSONObject["regex"] = null; delete myJSONObject["regex"]; 

这里的另一个重点是小心你对同一个对象的其他引用。 例如,如果你创build一个像这样的variables:

 var regex = myJSONObject["regex"]; 

或者把它作为一个新的指针添加到另一个对象,如:

 var myOtherObject = {}; myOtherObject["regex"] = myJSONObject["regex"]; 

然后,即使从对象myJSONObject删除它,该特定的对象也不会从内存中删除,因为regexvariables和myOtherObject["regex"]仍然有它们的值。 那么我们怎么能从内存中删除对象呢?

答案是删除代码中的所有引用,指向该对象也不使用var语句创build对该对象的新引用 。 关于var语句的最后一点是我们通常面临的最关键的问题之一,因为使用var语句将阻止创build的对象被删除。

这意味着在这种情况下,您将无法删除该对象,因为您已经通过var语句创build了regexvariables,如果您这样做:

 delete regex; //False 

结果将是false ,这意味着您的delete语句没有按照您的预期执行。 但是如果你之前没有创build这个variables,并且只有myOtherObject["regex"]作为最后一个现有的引用,那么你可以通过删除它来完成这个工作:

 myOtherObject["regex"] = null; delete myOtherObject["regex"]; 

换句话说,只要代码中没有指向该对象的引用,JavaScript对象就会被终止。


更新:感谢@AgentME:

在删除它之前将属性设置为null并不会完成任何操作(除非对象已被Object.seal密封,并且删除失败,除非特别尝试,否则通常不会这样做)。

获取更多关于Object.seal信息: Object.seal()

假设你有一个看起来像这样的对象:

 var Hogwarts = { staff : [ 'Argus Filch', 'Filius Flitwick', 'Gilderoy Lockhart', 'Minerva McGonagall', 'Poppy Pomfrey', ... ], students : [ 'Hannah Abbott', 'Katie Bell', 'Susan Bones', 'Terry Boot', 'Lavender Brown', ... ] }; 

删除对象属性

如果你想使用整个staff数组,正确的方法是做到这一点:

 delete Hogwarts.staff; 

或者,你也可以这样做:

 delete Hogwarts['staff']; 

同样,删除整个学生数组将通过调用delete Hogwarts.students;来完成delete Hogwarts.students;delete Hogwarts['students'];

删除数组索引

现在,如果你想删除一个工作人员或学生,程序有点不同,因为这两个属性本身就是数组。

如果你知道你的工作人员的指数,你可以简单地这样做:

 Hogwarts.staff.splice(3, 1); 

如果您不知道索引,则还必须执行索引search:

 Hogwarts.staff.splice(Hogwarts.staff.indexOf('Minerva McGonnagall') - 1, 1); 

注意

虽然技术上可以对数组使用delete ,但是稍后调用Hogwarts.staff.length时,使用它将导致得到不正确的结果。 换句话说, delete会删除元素,但不会更新length属性的值。 使用delete也会搞乱你的索引。

因此,从对象中删除值时,首先要考虑是处理对象属性还是处理数组值,并根据这些值select合适的策略。

如果你想尝试这个,你可以使用这个小提琴作为一个起点。

ECMAScript 2015(或ES6)带有内置的Reflect对象。 通过以目标对象和属性键为参数调用Reflect.deleteProperty()函数,可以删除对象属性:

 Reflect.deleteProperty(myJSONObject, 'regex'); 

相当于:

 delete myJSONObject['regex']; 

但是,如果对象的属性不可configuration,则不能使用deleteProperty函数或delete操作符删除它们:

 let obj = Object.freeze({ prop: "value" }); let success = Reflect.deleteProperty(obj, "prop"); console.log(success); // false console.log(obj.prop); // value 

Object.freeze()使对象的所有属性不可configuration(除了其他事物)。 deleteProperty函数(以及删除操作符 )尝试删除它的任何属性时返回false 。 如果属性是可configuration的,即使属性不存在,它也会返回true

deletedeleteProperty的区别在于使用严格模式时:

 "use strict"; let obj = Object.freeze({ prop: "value" }); Reflect.deleteProperty(obj, "prop"); // false delete obj["prop"]; // TypeError: property "prop" is non-configurable and can't be deleted 

删除操作符是最好的方式。

一个现场示例显示:

 var foo = {bar: 'bar'}; delete foo.bar; console.log('bar' in foo); // Logs false, because bar was deleted from foo. 

我个人使用Underscore.js进行对象和数组操作:

 myObject = _.omit(myObject, 'regex'); 

这篇文章是非常古老的,我发现它非常有帮助,所以我决定分享我写的未设置的function,以防其他人看到这篇文章,并认为它不是那么简单,因为它在PHP未设置的function。

编写这个新的未unset函数的原因是为了保留这个hash_map中所有其他variables的索引。 看下面的例子,看看从“hash_map”中删除一个值后,“test2”的索引是如何改变的。

 function unset(unsetKey, unsetArr, resort){ var tempArr = unsetArr; var unsetArr = {}; delete tempArr[unsetKey]; if(resort){ j = -1; } for(i in tempArr){ if(typeof(tempArr[i]) !== 'undefined'){ if(resort){ j++; }else{ j = i; } unsetArr[j] = tempArr[i]; } } return unsetArr; } var unsetArr = ['test','deletedString','test2']; console.log(unset('1',unsetArr,true)); // output Object {0: "test", 1: "test2"} console.log(unset('1',unsetArr,false)); // output Object {0: "test", 2: "test2"} 

这里有很多很好的答案,但是我只想在使用delete删除JavaScript中的一个属性时,首先检查该属性是否存在以防止错误通常是明智的。

例如

 var obj = {"property":"value", "property2":"value"}; if (obj && obj.hasOwnProperty("property2")) { delete obj.property2; } else { //error handling } 

由于JavaScript的dynamic特性,通常情况下你根本不知道属性是否存在。 在&&之前检查obj是否存在也确保你不会抛出一个错误,因为在未定义的对象上调用hasOwnProperty()函数。

对不起,如果这没有添加到您的具体用例,但我相信这是一个很好的devise,以适应pipe理对象及其属性。

另一个解决scheme,使用Array#reduce

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; myObject = Object.keys(myObject).reduce(function(obj, key) { if (key != "regex") { //key you want to remove obj[key] = myObject[key]; } return obj; }, {}); console.log(myObject); 

如果你想删除一个嵌套在对象中的属性,那么你可以使用下面的recursion函数作为第二个参数:

 var deepObjectRemove = function(obj, path_to_key){ if(path_to_key.length === 1){ delete obj[path_to_key[0]]; return true; }else{ if(obj[path_to_key[0]]) return deepObjectRemove(obj[path_to_key[0]], path_to_key.slice(1)); else return false; } }; 

例:

 var a = { level1:{ level2:{ level3: { level4: "yolo" } } } }; deepObjectRemove(a, ["level1", "level2", "level3"]); console.log(a); //Prints {level1: {level2: {}}} 

使用ramda#dissoc你会得到一个没有属性regex的新对象:

 const newObject = R.dissoc('regex', myObject); // newObject !== myObject 

您也可以使用其他function来实现相同的效果 – 省略,select,…

尝试以下方法。 将Object属性值分配给undefined 。 然后将对象stringifyparse

  var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; myObject.regex = undefined; myObject = JSON.parse(JSON.stringify(myObject)); console.log(myObject); 

使用delete方法是最好的方法,按照MDN描述,delete操作符从对象中删除一个属性。 所以你可以简单地写:

 delete myObject.regex; // OR delete myObject['regex']; 

删除操作符从对象中移除给定的属性。 删除成功后,将返回true,否则返回false。 但是,考虑以下情况很重要:

  • 如果您试图删除的属性不存在,删除将不起任何作用,并返回true

  • 如果在对象的原型链上存在一个同名的属性,那么在删除之后,对象将使用原型链中的属性(换句话说,删除只对自己的属性有影响)。

  • 用var声明的任何属性都不能从全局范围或函数的范围中删除。

  • 因此,删除不能删除全局范围内的任何函数(无论是从函数定义还是函数(expression式))。

  • 作为对象的一部分的function(除了
    全球范围)可以删除删除。

  • 用let或const声明的任何属性都不能从它们被定义的范围中删除。 不可configuration的属性不能被删除。 这包括诸如Math,Array,Object和属性等内置对象的属性,这些属性被创build为不可configuration的方法,如Object.defineProperty()。

下面的片段给出了另一个简单的例子:

 var Employee = { age: 28, name: 'abc', designation: 'developer' } console.log(delete Employee.name); // returns true console.log(delete Employee.age); // returns true // When trying to delete a property that does // not exist, true is returned console.log(delete Employee.salary); // returns true 

有关更多信息和查看更多示例,请访问下面的链接:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete

您可以使用delete关键字简单地删除对象的任何属性。

例如:

 var obj = {key1:"val1",key2:"val2",key3:"val3"} 

要删除任何属性,比如key1 ,请使用delete关键字,如下所示:

 delete obj.key1 

或者你也可以使用类似数组的表示法:

 delete obj[key1] 

Ref: MDN 。

尝试这个

 delete myObject['key']; 

丹的说法是“删除”是非常缓慢的,他发布的基准是怀疑。 所以我在Chrome 59中自己进行了testing。看起来“删除”大约慢了30倍:

 var iterationsTotal = 10000000; // 10 million var o; var t1 = Date.now(),t2; for (let i=0; i<iterationsTotal; i++) { o = {a:1,b:2,c:3,d:4,e:5}; delete oa; delete ob; delete oc; delete od; delete oe; } console.log ((t2=Date.now())-t1); // 6135 for (let i=0; i<iterationsTotal; i++) { o = {a:1,b:2,c:3,d:4,e:5}; oa = ob = oc = od = oe = undefined; } console.log (Date.now()-t2); // 205 

请注意,我在一个循环周期中执行了多个“删除”操作,以最大限度地减less其他操作造成的影响。

考虑创build一个没有"regex"属性的新对象,因为原始对象总是可以被程序的其他部分引用。 所以你应该避免操纵它。

 const myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; const { regex, ...newMyObject } = myObject; console.log(newMyObject); 

Object.assign()&Object.keys()&Array.map()

 const obj = { "Filters":[ { "FilterType":"between", "Field":"BasicInformationRow.A0", "MaxValue":"2017-10-01", "MinValue":"2017-09-01", "Value":"Filters value" } ] }; let new_obj1 = Object.assign({}, obj.Filters[0]); let new_obj2 = Object.assign({}, obj.Filters[0]); /* // old version let shaped_obj1 = Object.keys(new_obj1).map( (key, index) => { switch (key) { case "MaxValue": delete new_obj1["MaxValue"]; break; case "MinValue": delete new_obj1["MinValue"]; break; } return new_obj1; } )[0]; let shaped_obj2 = Object.keys(new_obj2).map( (key, index) => { if(key === "Value"){ delete new_obj2["Value"]; } return new_obj2; } )[0]; */ // new version! let shaped_obj1 = Object.keys(new_obj1).forEach( (key, index) => { switch (key) { case "MaxValue": delete new_obj1["MaxValue"]; break; case "MinValue": delete new_obj1["MinValue"]; break; default: break; } } ); let shaped_obj2 = Object.keys(new_obj2).forEach( (key, index) => { if(key === "Value"){ delete new_obj2["Value"]; } } ); 

你好,你可以尝试这种简单的sorting

 var obj = []; obj.key1 = {name: "John", room: 1234}; obj.key2 = {name: "Jim", room: 1234}; delete(obj.key1); 

使用lodash

 import omit from 'lodash/omit'; const prevObject = {test: false, test2: true}; // Removes test2 key from previous object const nextObject = omit(prevObject, 'test2'); 

使用Ramda

 R.omit(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, c: 3} 

您可以使用下面的delete操作符。

  var multiverse = { earth1: "Silver Age", earth2: "Golden Age" }; delete multiverse.earth2;//will return true if it finds // Outputs: { earth1: "Silver Age" } console.log(multiverse); 

删除操作符也有一个return value. 如果成功删除一个属性,它将返回true。 如果由于该属性不可写入而无法删除属性,它将return false ,或者如果处于严格模式,则会引发错误。

很简单:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; delete myObject.regex; 

我已经使用lodash“unset”来使嵌套对象也发生。只有这样才需要编写小逻辑来获取属性key的path,这是通过omit方法所期望的。

  1. 以数组的forms返回属性path的方法
 var a = {"bool":{"must":[{"range":{"price_index.final_price":{"gt":"450","lt":"500"}}},{"bool":{"should":[{"term":{"color_value.keyword":"Black"}}]}}]}}; function getPathOfKey(object,key,currentPath, t){ var currentPath = currentPath || []; for(var i in object){ if(i == key){ t = currentPath; } else if(typeof object[i] == "object"){ currentPath.push(i) return getPathOfKey(object[i], key,currentPath) } } t.push(key); return t; } document.getElementById("output").innerHTML =JSON.stringify(getPathOfKey(a,"price_index.final_price")) 
 <div id="output"> </div> 
 delete someObject["keyName"]; someObject["keyName"] // undefined