如何从JavaScript对象中删除属性?
假设我创建一个对象如下:
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);
对于任何有兴趣阅读更多关于它,堆栈溢出用户kangax写了一个令人难以置信的深入的博客文章对delete
自己的博客上声明,了解删除.强烈推荐.
- @Pete不,它确实删除了它.给定:`var x = {a:'A',b:'B'};`比较:`删除xa; typeof xa;/*"undefined"*/x.hasOwnProperty('a');/*false*/`到`xb = undefined; typeof xb;/*"undefined"*/; x.hasOwnProperty( 'B');/*true*/`
- 上面"理解删除"链接中的一个观察结果的结果是,因为您不一定要删除变量,而只能删除对象属性,因此您无法"通过引用"删除对象属性 - var value = obj [ '支柱']; 删除值//不起作用
- 选中,它也适用于"删除myJSONObject ['regex'];" 请参阅:http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/delete_Operator
- 所以它实际上并没有删除它?它只是变得未定义,但关键仍然存在?我错过了什么吗?
- @ChristopherPfohl为我工作.就像我说的那样,它实际上非常深入,所以总结起来有点困难.上面答案中的基本响应对于几乎所有情况都是足够的,博客进入了更多边缘案例以及这些案例存在的原因.
- @GeorgeJempty您可以在`delete`表达式中为属性名称本身使用变量:`var x ='x'; 删除对象[x];`
- 使用JS Strict模式时禁止`delete`禁止?[doc on strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode).使用严格模式时如何删除属性?
操作员delete
出乎意料地慢了!
看看基准.
删除是删除对象属性而没有任何剩余物的唯一真正方法,但与其"替代"设置相比,它的工作速度慢约100倍object[key] = undefined
.
这个替代方案不是这个问题的正确答案!但是,如果你小心使用它,你可以大大加快一些算法.如果您delete
在循环中使用并且遇到性能问题,请阅读详细说明.
应该delete
何时使用,何时设定值undefined
?
对象可以被视为一组键值对.我称之为'值'的是原始的或对其他对象的引用,与该'key'相关联.
使用delete
,当你路过结果对象的代码上,你就不用管了(或者当你不知道你的团队或自己).
它从hashmap中删除密钥.
var obj = {
field: 1
};
delete obj.field;
使用设置undefined
,当你关心性能.它可以大大提升您的代码.
将其在HashMap中的地方重点遗体,只有值被替换undefined
.明白,该for..in
循环仍然会遍历该密钥.
var obj = {
field: 1
};
obj.field = undefined;
使用此方法,并非所有确定属性存在的方法都将按预期工作.
但是,这段代码:
object.field === undefined
两种方法的行为都相同.
测试
总而言之,差异是关于确定属性存在的方式和for..in
循环.
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 that runs much slower :)
var counter = 0,
key;
for (key in obj) {
counter++;
}
console.assert(counter === 0, 'counter === 0', '"field" is not iterated using "for .. in" loop. *');
小心内存泄漏!
虽然使用obj[prop] = undefined
比做更快delete obj[prop]
,但另一个重要的考虑因素obj[prop] = undefined
可能并不总是合适的.delete obj[prop]
除去prop
从obj
和从存储器擦除它,而obj[prop] = undefined
简单地设置的值prop
,以undefined
留下prop
仍然在存储器中.因此,在创建和删除许多密钥的情况下,使用obj[prop] = undefined
可能会强制进行昂贵的内存协调(导致页面冻结)并可能导致内存不足错误.检查以下代码.
"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
nodeRecords[i] = [];
current = theNodeList[i] = document.createElement("div");
current.textContent = i;
document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
var currentTime = Math.round( performance.now()*1000 )
for (i = 0; i !== numberOfNodes; i++) {
if (lastTime !== -1) {
// the previously collected data is no longer in use
/*************************************************/
/****/ nodeRecords[i][lastTime] = undefined; /****/
/*************************************************/
}
nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
}
lastTime = currentTime;
requestAnimationFrame( recordUpdates );
});
在上面的代码中,简单地执行nodeRecords[i][lastTime] = undefined;
将导致大量内存泄漏,因为每个动画帧.每个帧,所有65536个DOM元素将占用另外65536个单独的插槽,但之前的65536个插槽只会被设置为未定义,这会使它们挂在内存中.来吧,尝试在控制台中运行上面的代码并亲自查看.强制出现内存不足错误后,尝试再次运行它,除非使用以下版本的代码使用delete
运算符.
"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
nodeRecords[i] = [];
current = theNodeList[i] = document.createElement("div");
current.textContent = i;
document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
var currentTime = Math.round( performance.now()*1000 )
for (i = 0; i !== numberOfNodes; i++) {
if (lastTime !== -1) {
// the previously collected data is no longer in use
/********************************************/
/****/ delete nodeRecords[i][lastTime]; /****/
/********************************************/
}
nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
}
lastTime = currentTime;
requestAnimationFrame( recordUpdates );
});
如上面的代码片段所示,delete
运算符有一些罕见的适当用例.但是,不要太担心这个问题.这只会成为长寿命对象的问题,这些对象会不断添加新密钥.在任何其他情况下(几乎在实际编程中都是这种情况),最适合使用obj[prop] = undefined
.本节的主要目的只是为了引起您的注意,以便在您的代码中这很可能成为一个问题,那么您可以更轻松地理解问题,从而不必浪费时间来解析您的代码来定位并了解这个问题.
不要总是设置为 undefined
Javascript的一个重要考虑因素是多态性.多态性是指分配相同变量/对象中的不同类型,如下所示.
var foo = "str";
foo = 100; // variable foo is now labeled polymorphic by the browser
var bar = ["Some", "example"];
bar[2] = "text"; // bar is a monomorphic array here because all its entries have the
// same type: string primitive
bar[1] = undefined; // bar is now a polymorphic array
但是,多态数组有两个主要的无法解决的问题:
- 它们速度慢,内存效率低.当访问特定索引时,浏览器不必仅获取数组的全局类型,而是必须基于每个索引获取类型,从而每个索引都存储其类型的其他元数据.
- 一旦多态,总是多态的.当一个数组变成多态时,多态性无法在Webkit浏览器中撤消.因此,即使您将多态数组还原为非多态数组,它仍将被浏览器存储为多态数组.
人们可能将多态性比作药物成瘾.乍一看,它似乎非常有利可图:漂亮的蓬松代码.然后,编码器将他们的阵列引入多态性药物.即时地,多态数组变得效率较低,并且由于它是药物,它永远不会像以前那样有效.为了将这种情况与现实生活联系起来,可卡因的某些人甚至可能无法操作简单的门把手,更不用说能够计算PI的数字了.同样,多态性药物上的阵列也不能像单态阵列那样有效.
但是,药物旅行类比如何与delete
手术相关?答案在上面的代码片段中包含了最后一行代码.因此,让它重新审视,这次是扭曲.
var bar = ["Some", "example"];
bar[2] = "text"; // bar is not a polymorphic array here because all its entries have the
// same type: string primitive
bar[1] = ""; // bar is still a monomorphic array
bar[1] = undefined; // bar is now a polymorphic array
观察.bar[1] = ""
不会强迫多态,bar[1] = undefined
而是.因此,应该始终尽可能为对象使用相应的类型,以免意外地导致多态性.一个这样的人可以使用以下列表作为一般参考来使他们前进.但是,请不要明确使用以下想法.相反,使用任何适用于您的代码的方法.
- 使用类型为布尔基元的数组/变量时,请使用
false
或undefined
作为空值.虽然避免不必要的多态性是好的,但重写所有代码以明确禁止它可能实际上会导致性能下降.使用共同的判断! - 使用键入数字原语的数组/变量时,请将其
0
用作空值.请注意,在内部,有两种类型的数字:快速整数(包括2147483647到-2147483648)和慢浮点双精度(除此之外的任何其他包括NaN
和Infinity
).当一个整数降级为double时,它不能被提升回整数. - 使用键入字符串基元的数组/变量时,请将其
""
用作空值. - 使用符号时,请等待,为什么使用符号?!?!符号是表现糟糕的juju.编程为使用符号的所有内容都可以重新编程为不使用符号,从而产生没有符号的更快代码.符号实际上只是超低效的元糖.
- 使用其他任何东西时,请使用
null
.
不过,请注意!现在不要突然开始使用所有预先存在的代码执行此操作,因为它可能会破坏此类预先存在的代码和/或引入奇怪的错误.相反,这种有效的实践需要从一开始就实现,并且在转换预先存在的代码时,建议您对所有与之相关的行进行双倍,三倍,四倍检查,因为尝试将旧代码升级到此新实践可以是有风险,因为它是有益的.
- 属性被指定为undefined仍然是对象的属性,因此它不会被GC删除,除非误读了你的最后一段.
- *属性被指定为undefined仍然是对象的属性,因此它不会被GC删除*GC不会管理任何有关属性的内容.它收集和删除值.只要没有任何内容引用值(对象,字符串等),GC就会将其从内存中删除.
- 我在这里触摸GC的主题是错误的.两种方法对GC都有相同的结果:它们删除链接到键的值.如果该值是对其他某个对象的最后一个引用,则该对象将被清除.
- 顺便说一句,这是检查Javascript对象上是否存在属性的双重问题.使用*in*运算符是可靠的但很慢.检查属性是否*未定义*"不是正确的答案",但它更快.[检查](http://stackoverflow.com/questions/1098040/checking-if-an-array-key-exists-in-a-javascript-object-or-array/22074727#22074727)
- 这个答案是否仍然相关?jsperf目前正在下降,但是[这个基准](http://jsben.ch/#/gu1Gi)似乎表明速度差仅为25%,这对于_"〜慢100倍"_无处可去在这个答案.
- 现在,在2017年底,`delete`仍然比JSPerf测试中的其他"替代"慢98%.但是,在比较事物时,必须在所有情况下使用_same standards_.不言而喻,删除属性,无论是否使用`delete`或任何其他功能,都将*总是*比为该属性赋值更慢,即使是100年后也是如此.就像从网页上删除按钮总是比以透明颜色绘制它更慢 - 它们是不同的操作,也就是用于比较的"不同标准"...
var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
delete myObject.regex;
console.log ( myObject.regex); // logs: undefined
这适用于Firefox和Internet Explorer,我认为它适用于所有其他人.
更新2018-07-21:很长一段时间,我对这个答案感到尴尬,所以我觉得是时候把它搞定了一点.只需要一点评论,澄清和格式化,以帮助加快阅读这个答案中不必要的漫长而复杂的部分.
短版
这个问题的实际答案
正如其他人所说,你可以使用delete
.
obj // {"foo": "bar"}
delete obj["foo"]
obj // {}
obj["foo"] // undefined
数组等价
不要delete
从阵列.请Array.prototype.splice
改用.
arr // [1,2,3,4,5]
arr.splice(3,1); // 4
arr // [1,2,3,5]
长版
JavaScript是一种OOP语言,所以一切都是对象,包括数组.因此,我认为有必要指出一个特别的警告.
在数组中,与普通的旧对象不同,使用delete
垃圾形式的叶子null
,在数组中创建一个"洞".
var array = [1, 2, 3, 4];
delete array[2];
/* Expected result --> [1, 2, 4]
* Actual result --> [1, 2, null, 4]
*/
正如您所看到的,delete
并不总是像人们期望的那样工作.该值被覆盖,但内存未重新分配.也就是说,array[4]
没有重新安置array[3]
.与之相反Array.prototype.unshift
,它在数组的开头插入一个元素并将所有内容都移位(array[0]
变为array[1]
等)
老实说,除了设置null
而不是undefined
,可呈现为合法怪异-这种行为不应该是不足为奇的,因为delete
是一元运算符,如typeof
,那就是煮到语言,不应该在乎类型的对象正在被使用,而是使用专门用于处理数组的方法Array
的子类.所以没有充分的理由让一个特殊的盒子用于重新移动阵列,因为这会减少不必要的工作.回想起来,我的期望是不现实的.Object
delete
当然,这也让我感到吃惊.因为我写这篇文章是为了证明我对"空垃圾"的讨伐:
这是摆脱了可怕的理由null
S-- null
只危险的,如果使用不当,它没有任何与"精确".你不应该delete
从一个数组的真正原因是因为留下垃圾填充和混乱的数据结构是草率和容易出错.
接下来是一个非常冗长的人为场景,如果你愿意,可以跳到解决方案部分.我离开这一部分的唯一原因是因为我认为有些人可能认为这很有趣,而且我不想成为那个发表"有趣"答案然后从中删除所有"有趣"的"那个人". .
......我知道,这很愚蠢.
设计和冗长的PDP-11场景
好吧,让我们只想说,你想在这个请求节省内存一个谁运行,从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
问题,你仍然需要取悦那个trollPDP-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.splice()
.你可以写这样的东西:
Array.prototype.remove = function(index){
this.splice(index,1);
}
...
array = [1, 2, 3, 4];
array.remove(2);
// Result -> [1, 2, 4]
就这样,你很高兴PDP-11先生.万岁!(我还是告诉他,不过......)
Array.prototype.splice vs Array.prototype.slice
我觉得指出这两个同名的函数之间的区别非常重要,因为它们都非常有用.
Array.prototype.splice(start,n)
.splice()
改变数组,并返回删除的索引.从索引开始切割数组start
,并n
切出元素.如果未指定n,则将整个数组start
切出(n = array.length - start
).
let a = [5,4,3,2,1];
let chunk = a.splice(2,2);
// a [5,4,3,2,1]
// start 0 1 2 - -
// n - - 1 2 -
chunk; // [3,2]
a; // [5,4,1]
Array.prototype.slice(开始,结束)
.slice()
是非破坏性的,并返回从含有指示索引的新的数组start
,以end
.如果end
未指定,则行为与.splice()
(end = array.length
)相同.这个行为有点棘手,因为由于某种原因,end
索引从1而不是0.我不知道为什么会这样做,但事实就是如此.另外,如果end <= start
,结果是一个空数组.
let a = [5,4,3,2,1];
let chunks = [
a.slice(2,0),
a.slice(2,2),
a.slice(2,3),
a.slice(2,5) ];
// a [5,4,3,2,1]
// start 0 1 2 - -
// end, for... - - - - -
// chunks[0] 0 - - - - -
// chunks[1] 1 2 - - -
// chunks[2] 1 2 3 - -
// chunks[3] 1 2 3 4 5
chunks; // [ [], [], [3], [3,2,1] ]
a; // [5,4,3,2,1]
这实际上不是正在发生的事情,但更容易想到这种方式.根据MDN,这是实际发生的事情:
// a [5,4,3,2,1]
// start 0 1 2 - - -
// end, for... - - - - - -
// chunks[0] 0 - - - - -
// chunks[1] 0 1 2 - - -
// chunks[2] 0 1(2)3 - -
// chunks[3] 0 1(2 3 4)5
指定的索引end
只是从切片中排除.带括号的索引表示切片的内容.无论哪种方式,行为都不直观,并且它必然导致其公平分享一个一个错误,因此您可能会发现使包装函数更接近地模拟以下行为是有用的.splice()
:
function ez_slice(array, start = 0, n = null){
if(!Array.isArray(array) || !is_number(start))
return null;
if(is_number(n))
return array.slice(start, start + n);
if(n === null)
return array.slice(start);
return null;
}
ez_slice([5,4,3,2,1], 2, 1) // [3]
ez_slice([5,4,3,2,1], 2) // [3,2,1]
/* Fun fact: isNaN is unreliable.
* [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(isNaN)
* [NaN, {}, undefined, "Hi"]
*
* What we want is...
*
* [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(is_nan)
* [NaN]
*/
function is_nan(num){
return typeof num === "number"
&& num !== num;
}
function is_number(num){
return !is_nan(num)
&& typeof num === "number"
&& isFinite(num);
}
请注意,包装函数的设计对类型非常严格,null
如果有任何关闭则会返回.这包括输入一个字符串"3"
.程序员需要勤勉地研究他的类型.这是为了鼓励良好的编程实践.
有关的更新 is_array()
这是关于这个(现在删除)的片段:
function is_array(array){
return array !== null
&& typeof array === "object"
&& typeof array.length !== "undefined"
&& array.__proto__ === Array.prototype;
}
事实证明,实际上有一种内置的方法来判断一个数组是否真的是一个数组,这就是Array.isArray()
在ECMAScript 5(2009年12月)中引入的.我找到了这个,同时查看是否有一个问题询问是否从对象告诉数组,看看是否有比我更好的解决方案,或者如果没有,则添加我的.因此,如果您使用的是早于ECMA 5的JavaScript版本,那么就是您的polyfill.但是,我强烈建议不要使用我的is_array()
功能,因为继续支持旧版本的JavaScript意味着继续支持实现它们的旧浏览器,这意味着鼓励使用不安全的软件并使用户面临恶意软件的风险.所以,请使用Array.isArray()
.使用let
和const
.使用添加到该语言的新功能.不要使用供应商前缀.从您的网站删除 IE polyfill废话.删除那个XHTML <!CDATA[[...
废话 - 我们在2014年转移到HTML5.每个人都越早撤回对那些旧/深奥浏览器的支持,浏览器供应商越早实际遵循Web标准并采用新技术,我们越早能够转向更安全的网络.
- @ B1KMusic以下是从数组中删除元素的方法:[splice](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/splice)
- 然而,这个`delete`关键字更方便,哈哈
- 此方法不会修改可能仍在其他地方引用的原始对象.这可能是也可能不是问题,取决于它是如何使用的,但要记住这一点.
- 我在编辑中没有看到`splice`,但`remove`应该是`Array.prototype.remove = function(index){this.splice(index,1); };`
- @wulftone nope,分割数组并没有删除任何值.我真的认为从需要删除特定值的数组中删除的最佳方法是使用`delete`并使用垃圾收集功能来清理它.
老问题,现代答案.使用对象解构,ECMAScript 6功能,它很简单:
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试用编辑器中看到它的运行情况.
编辑:
要重新分配到同一个变量,请使用let
:
let myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
({ regex, ...myObject } = myObject);
console.log(myObject);
- 问题陈述"最终得到**新**myObject".
- 也许是因为目标是从对象中删除属性,而不是在没有属性的情况下创建新属性...尽管如此,您的解决方案是我最喜欢的,因为我更喜欢不可变的方式.
- @PranayKumar我希望这种语法能起作用;const {[key],... newObject} = myObject;`但事实并非如此,因此我认为解构是不可能的。
- 使用`freeze()`'d和`seal()`'d对象,你不能简单地`删除'一个属性.所以这是一个很好的选择.虽然在大多数情况下,从冻结/密封的对象中删除属性可能没有意义,考虑到整个要点是对您的数据结构做出某些保证,这种模式将会破坏.对于那些需要非破坏性地欺骗对象但没有某些属性的情况,这是完美的
另一种方法是使用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()
可以以类似的方式使用.
- 请记住,如果对象的键是数字,则可能需要`_.omit(collection,key.toString())`
传播语法(ES6)
无论谁需要它......
要在此线程中完成@Koen答案,如果您想使用扩展语法删除动态变量,您可以这样做:
const key = 'a';
const { [key]: foo, ...rest } = { a: 1, b: 2, c: 3 };
console.log(rest); // { b: 2, c: 3 }
*foo
将是一个值为a
(为1)的新变量.
更新:
从对象中删除属性的常用方法很少.
每个人都有自己的优点和缺点(检查这个性能比较):
删除操作符
可读且简短,但如果您对大量对象进行操作,则可能不是最佳选择,因为其性能未得到优化.
delete obj[key];
重新分配
速度超过2倍delete
,但该属性未被删除且可以迭代.
obj[key] = null;
obj[key] = false;
obj[key] = undefined;
Spread Operator
此ES6
操作符允许我们返回一个全新的对象,不包括任何属性,而不会改变现有对象.缺点是它具有较差的性能,并且当您需要一次删除许多属性时不建议使用它.
{ [key]: val, ...rest } = obj;
- the best answer without altering original object!
您在问题标题中使用的术语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"]
但关键是如果你关心内存并且想要整个对象从内存中删除,建议在删除密钥之前将其设置为null:
myJSONObject["regex"] = null;
delete myJSONObject["regex"];
这里另一个重点是要小心你对同一个对象的其他引用.例如,如果您创建一个变量,如:
var regex = myJSONObject["regex"];
或者将其添加为另一个对象的新指针,如:
var myOtherObject = {};
myOtherObject["regex"] = myJSONObject["regex"];
然后,即使您从对象中删除它myJSONObject
,该特定对象也不会从内存中删除,因为该regex
变量myOtherObject["regex"]
仍然具有其值.那么我们怎么能从内存中删除对象呢?
答案是删除代码中的所有引用,指向该对象,也不使用var
语句来创建对该对象的新引用.关于var
语句的最后一点是我们通常面临的最关键问题之一,因为使用var
语句会阻止创建的对象被删除.
这意味着在这种情况下,您将无法删除该对象,因为您已regex
通过var
语句创建了变量,如果您这样做:
delete regex; //False
结果将是false
,这意味着您的删除语句尚未按预期执行.但是,如果您之前没有创建过该变量,并且只有myOtherObject["regex"]
最后一个现有引用,那么您可以通过删除它来完成此操作,如:
myOtherObject["regex"] = null;
delete myOtherObject["regex"];
换句话说,只要代码中没有指向该对象的引用,JavaScript对象就会被终止.
更新:
感谢@AgentME:
要获得更多信息Object.seal
:Object.seal()
ECMAScript 2015(或ES6)带有内置的Reflect对象.可以通过使用目标对象和属性键作为参数调用Reflect.deleteProperty()函数来删除对象属性:
Reflect.deleteProperty(myJSONObject, 'regex');
这相当于:
delete myJSONObject['regex'];
但是如果对象的属性不可配置,则不能使用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()使对象的所有属性都不可配置(除了其他东西).deleteProperty
函数(以及删除运算符)false
在尝试删除其任何属性时返回.如果属性是可配置的,则返回true
,即使属性不存在也是如此.
delete
和之间的区别在于deleteProperty
使用严格模式:
"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 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'];
.
删除数组索引
现在,如果要删除单个工作人员或学生,则该过程会有所不同,因为这两个属性本身都是数组.
如果您知道工作人员的索引,您可以这样做:
Hogwarts.staff.splice(3, 1);
如果你不知道索引,你还必须进行索引搜索:
Hogwarts.staff.splice(Hogwarts.staff.indexOf('Minerva McGonnagall') - 1, 1);
注意
虽然您在技术上可以delete
用于数组,但使用它会导致在Hogwarts.staff.length
稍后调用时获得不正确的结果.换句话说,delete
将删除元素,但它不会更新length
属性的值.使用delete
也会搞砸你的索引.
因此,在从对象中删除值时,始终首先考虑您是在处理对象属性还是处理数组值,并根据它选择适当的策略.
如果你想试验这个,你可以用这个小提琴作为起点.
使用ES6:
(解构+传播运营商)
const myObject = {
regex: "^http://.*",
b: 2,
c: 3
};
const { regex, ...noRegex } = myObject;
console.log(noRegex); // => { b: 2, c: 3 }
该delete运算符是这样做的最佳方式.
一个实例展示:
var foo = {bar: 'bar'};
delete foo.bar;
console.log('bar' in foo); // Logs false, because bar was deleted from foo.
我个人使用Underscore.js或Lodash的对象和数组操作:
myObject = _.omit(myObject, 'regex');
使用delete方法是最好的方法,根据MDN描述,delete运算符从对象中删除属性.所以你可以简单地写:
delete myObject.regex;
// OR
delete myObject['regex'];
以下代码段提供了另一个简单示例:
var Employee = {
age: 28,
name: 'Alireza',
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
使用另一个解决方案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);
但是,它会改变原始对象.如果要创建没有指定键的新对象,只需将reduce函数指定给新变量,例如:
(ES6)
const myObject = {
ircEvent: 'PRIVMSG',
method: 'newURI',
regex: '^http://.*',
};
const myNewObject = Object.keys(myObject).reduce((obj, key) => {
key !== 'regex' ? obj[key] = myObject[key] : null;
return obj;
}, {});
console.log(myNewObject);
克隆没有属性的对象:
例如:
let object = { a: 1, b: 2, c: 3 };
而且我们需要删除“ a”。
1.带有明确的道具键:
const { a, ...rest } = object;
object = rest;
2.带可变道具键:
const propKey = 'a';
const { [propKey]: propValue, ...rest } = object;
object = rest;
3,酷箭头功能:
const removePropery = (propKey, { [propKey]: propValue, ...rest }) => rest;
object = removePropery('a', object);
4.对于多个属性
const removeProperties = (object, ...keys) => Object.entries(object).reduce((prev, [key, value]) => ({...prev, ...(!keys.includes(key) && { [key]: value }) }), {})
用法
object = removeProperties(object, 'a', 'b') // result => { c: 3 }
要么
const propsToRemove = ['a', 'b']
object = removeProperties(object, ...propsToRemove) // result => { c: 3 }
这篇文章非常陈旧,我发现它非常有用,所以我决定分享我写的未设置的函数,以防其他人看到这篇文章,并想想为什么它不像PHP unset函数那么简单.
编写这个新unset
函数的原因是保留此hash_map中所有其他变量的索引.查看以下示例,并查看从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的动态特性,通常情况下您根本不知道该属性是否存在.在&&之前检查是否存在obj还确保由于在未定义的对象上调用hasOwnProperty()函数而不抛出错误.
很抱歉,如果这没有添加到您的特定用例,但我相信这是一个很好的设计,以适应管理对象及其属性.
- 即使栏不存在,删除foo.bar仍然有效,所以你的测试有点太多,恕我直言.
- `delete foo.bar;`如果foo是假的,只会抛出异常,或者如果你处于严格模式,foo是一个具有不可配置bar属性的对象.
使用ramda#dissoc,你将得到一个没有属性的新对象regex
:
const newObject = R.dissoc('regex', myObject);
// newObject !== myObject
您还可以使用其他功能来实现相同的效果 - 省略,选择,...
请尝试以下方法.将Object
属性值分配给undefined
.然后stringify
是对象和parse
.
var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
myObject.regex = undefined;
myObject = JSON.parse(JSON.stringify(myObject));
console.log(myObject);
如果要删除深度嵌套在对象中的属性,则可以使用以下递归函数和属性路径作为第二个参数:
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: {}}}
这是一种轻松删除条目的 ES6 方法:
let myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
const removeItem = 'regex';
const { [removeItem]: remove, ...rest } = myObject;
console.log(remove); // "^http://.*"
console.log(rest); // Object { ircEvent: "PRIVMSG", method: "newURI" }
使用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}
@johnstock,我们还可以使用 JavaScript 的原型概念向对象添加方法,以删除调用对象中可用的任何传递键。
以上答案表示赞赏。
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
// 1st and direct way
delete myObject.regex; // delete myObject["regex"]
console.log(myObject); // { ircEvent: 'PRIVMSG', method: 'newURI' }
// 2 way - by using the concept of JavaScript's prototyping concept
Object.prototype.removeFromObjectByKey = function(key) {
// If key exists, remove it and return true
if (this[key] !== undefined) {
delete this[key]
return true;
}
// Else return false
return false;
}
var isRemoved = myObject.removeFromObjectByKey('method')
console.log(myObject) // { ircEvent: 'PRIVMSG' }
// More examples
var obj = {
a: 45,
b: 56,
c: 67
}
console.log(obj) // { a: 45, b: 56, c: 67 }
// Remove key 'a' from obj
isRemoved = obj.removeFromObjectByKey('a')
console.log(isRemoved); //true
console.log(obj); // { b: 56, c: 67 }
// Remove key 'd' from obj which doesn't exist
var isRemoved = obj.removeFromObjectByKey('d')
console.log(isRemoved); // false
console.log(obj); // { b: 56, c: 67 }
您可以使用如下过滤器
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
// Way 1
let filter1 = {}
Object.keys({...myObject}).filter(d => {
if(d !== 'regex'){
filter1[d] = myObject[d];
}
})
console.log(filter1)
// Way 2
let filter2 = Object.fromEntries(Object.entries({...myObject}).filter(d =>
d[0] !== 'regex'
))
console.log(filter2)
您可以使用delete
关键字删除对象的任何属性.
例如:
var obj = {key1:"val1",key2:"val2",key3:"val3"}
要删除任何属性,请key1
使用以下delete
关键字:
delete obj.key1
或者您也可以使用类似数组的表示法:
delete obj[key1]
参考:MDN.
我已经使用Lodash "unset"使其也适用于嵌套对象......只需要编写小逻辑来获取omit方法预期的属性键的路径。
- 将属性路径作为数组返回的方法
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>
</div>
- 然后只需使用Lodash unset方法从对象中删除属性。
var unset = require('lodash.unset');
unset(a, getPathOfKey(a, "price_index.final_price"));
丹的断言"删除"非常缓慢,而他发布的基准则受到怀疑.所以我自己在Chrome 59中进行了测试.看起来'删除'的速度慢了大约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 o.a; delete o.b; delete o.c; delete o.d; delete o.e;
}
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};
o.a = o.b = o.c = o.d = o.e = undefined;
}
console.log (Date.now()-t2); // 205
请注意,我有意在一个循环周期中执行多个"删除"操作,以最大限度地减少其他操作所造成的影响.
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"];
}
}
);
考虑创建一个没有"regex"
属性的新对象,因为原始对象总是可以被程序的其他部分引用.因此你应该避免操纵它.
const myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
const { regex, ...newMyObject } = myObject;
console.log(newMyObject);
const myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
const { regex, ...other } = myObject;
console.log(myObject)
console.log(regex)
console.log(other)
您可以将ES6解构与rest运算符一起使用。
可以通过与rest运算符结合使用分解来删除属性。在您的示例中,正则表达式被解构(忽略),其余属性作为其余部分返回。
const noRegex = ({ regex, ...rest }) => rest;
const myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
console.log(noRegex(myObjext)) //=> { "ircEvent": "PRIVMSG","method": "newURI" }
或者您可以动态排除此类属性,
const myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
const removeProperty = prop => ({ [prop]: _, ...rest }) => rest
const removeRegex = removeProperty('regex') //=> { "ircEvent": "PRIVMSG","method":"newURI" }
const removeMethod = removeProperty('method') //=> { "ircEvent": "PRIVMSG", "regex":"^http://.*" }
试试这个
delete myObject['key'];
您好,您可以尝试这种简单的排序
var obj = [];
obj.key1 = {name: "John", room: 1234};
obj.key2 = {name: "Jim", room: 1234};
delete(obj.key1);
JavaScript中的属性移除
此页面上提供了许多不同的选项,不是因为大多数选项是错误的,或者是答案是重复的,而是因为适当的技术取决于您所处的情况以及您和/或您的任务目标团队正在努力实现。要明确回答您的问题,您需要知道:
- 您要定位的ECMAScript版本
- 您要删除其属性的对象类型范围以及需要忽略的属性名称类型(仅字符串?符号?从任意对象映射的引用弱?这些年来,它们一直是JavaScript中的属性指针类型)
- 您和您的团队使用的编程精神/模式。您是否偏爱功能性方法,并且团队中的突变是根深蒂固的,还是您采用了狂野西部突变的面向对象技术?
- 您是要使用纯JavaScript实现这一目标,还是愿意并能够使用第三方库?
回答完这四个查询后,为了满足您的目标,JavaScript中实际上有四个类别的“属性删除”可供选择。他们是:
可变对象属性删除,不安全
当您想要保留/继续使用原始引用并且在代码中不使用无状态功能原理时,此类别用于对对象文字或对象实例进行操作。此类别中的一个示例语法:
'use strict'
const iLikeMutatingStuffDontI = { myNameIs: 'KIDDDDD!', [Symbol.for('amICool')]: true }
delete iLikeMutatingStuffDontI[Symbol.for('amICool')] // true
Object.defineProperty({ myNameIs: 'KIDDDDD!', 'amICool', { value: true, configurable: false })
delete iLikeMutatingStuffDontI['amICool'] // throws
此类别是属性删除的最古老,最直接和最广泛支持的类别。Symbol
除了字符串之外,它还支持&数组索引,并且在第一个JavaScript版本中均可使用,除了第一个发行版。但是,它是变异的,违反了一些编程原则,并且对性能有影响。在严格模式下在不可配置的属性上使用时,也会导致未捕获的异常。
基于休息的字符串属性遗漏
当需要使用非可变方法并且您不需要考虑符号键时,此类别用于在较新的ECMAScript样式中对纯对象或数组实例进行操作。
const foo = { name: 'KIDDDDD!', [Symbol.for('isCool')]: true }
const { name, ...coolio } = foo // coolio doesn't have "name"
const { isCool, ...coolio2 } = foo // coolio2 has everything from `foo` because `isCool` doesn't account for Symbols :(
可变对象属性删除,安全
当您要保留/继续使用原始引用,同时防止在不可配置的属性上引发异常时,此类别用于处理对象文字或对象实例。
'use strict'
const iLikeMutatingStuffDontI = { myNameIs: 'KIDDDDD!', [Symbol.for('amICool')]: true }
Reflect.deleteProperty(iLikeMutatingStuffDontI, Symbol.for('amICool')) // true
Object.defineProperty({ myNameIs: 'KIDDDDD!', 'amICool', { value: true, configurable: false })
Reflect.deleteProperty(iLikeMutatingStuffDontI, 'amICool') // false
此外,尽管就地改变对象不是无状态的,但您可以使用的功能性质Reflect.deleteProperty
来执行部分应用程序和其他delete
语句无法实现的功能技术。
基于语法的字符串属性省略
当需要使用非可变方法并且您不需要考虑符号键时,此类别用于在较新的ECMAScript样式中对纯对象或数组实例进行操作。
const foo = { name: 'KIDDDDD!', [Symbol.for('isCool')]: true }
const { name, ...coolio } = foo // coolio doesn't have "name"
const { isCool, ...coolio2 } = foo // coolio2 has everything from `foo` because `isCool` doesn't account for Symbols :(
基于图书馆的财产遗漏
通常,此类别可提供更大的功能灵活性,包括考虑符号并在一个语句中省略多个属性:
const o = require("lodash.omit")
const foo = { [Symbol.for('a')]: 'abc', b: 'b', c: 'c' }
const bar = o(foo, 'a') // "'a' undefined"
const baz = o(foo, [ Symbol.for('a'), 'b' ]) // Symbol supported, more than one prop at a time, "Symbol.for('a') undefined"