如何从JavaScript对象中删除属性?

说我创建一个对象,如下所示:

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

删除属性regex以产生新的myObject的最佳方法是什么?

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

#1楼

2018年7月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语言,因此所有内容都是一个对象,包括arrays 。 因此,我觉得有必要指出一个特别的警告。

在数组中,与普通的旧对象不同,使用deletenull的形式在垃圾后面留下垃圾,从而在数组中创建一个“空洞”。

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 ,也就是煮到语言和不应该照顾关于它所使用的对象的类型 ,而ArrayObject的子类,具有专门用于处理数组的方法。 因此,没有充分的理由delete来准备特殊情况以重新移动阵列,因为那样只会因不必要的工作而减慢速度。 回想起来,我的期望是不现实的。

当然,这确实让我感到惊讶。 因为我写这是为了证明我的运动反对“空垃圾”:

忽略null固有的危险和问题以及浪费的空间,如果数组需要精确,则可能会出现问题。

这是摆脱了可怕的理由null S-- null只危险的,如果使用不当,它没有任何与“精确”。 您不应该从数组中delete的真正原因是留下乱七八糟的数据结构是草率且容易出错的。

接下来是一个人为scenario绕的人为场景,因此,如果需要,您可以跳至解决方案部分。 我离开本节的唯一原因是,我认为某些人可能认为这很有趣,并且我不想成为发布“搞笑”答案然后随后删除所有“搞笑”内容的“那个人” 。

...这很愚蠢,我知道。

人为和漫长的PDP-11方案

例如,假设您正在创建一个使用JSON序列化的Web应用程序,以将用于“选项卡”的数组存储在字符串中(本例中为localStorage )。 我们还说,代码在绘制到屏幕时使用数组成员的数字索引为它们“添加标题”。 您为什么要这样做,而不仅仅是存储“标题”? 因为... 原因

好吧,让我们只想说,你想在这个用户是谁运行UNIX 1960年运行的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问题,您仍然必须请那个巨魔 PDP-11用户使用。 las,他的计算机没有足够的内存来容纳最后一个整数(不要问他如何处理可变宽度数组...)

因此,他很生气地向您发送了一封电子邮件:

 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.slice与Array.prototype.slice

我觉得有必要指出这两个相似命名的函数之间的区别,因为它们都很有用。

Array.prototype.splice(start,n)

.splice()数组,并返回删除的索引。 从索引index 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()是非破坏性的,并返回包含所指示的索引从一个新的数组startend 。 如果未指定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()的行为.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;
}

事实证明,实际上存在一种内置方法来判断数组是否确实是数组,这就是ECMAScript 5(2009年12月)中引入的Array.isArray() )。 我在寻找是否有一个问题来询问对象数组时发现了这一点,以查看是否有比我的解决方案更好的解决方案,或者是否有没有比我的解决方案更好的解决方案。 因此,如果您使用的JavaScript版本早于ECMA 5,则可以使用polyfill。 但是,我强烈建议不要使用is_array()函数,因为继续支持旧版本的JavaScript意味着继续支持实现旧版本JavaScript的浏览器,这意味着鼓励使用不安全的软件,并使用户面临遭受恶意软件威胁的危险。 因此,请使用Array.isArray() 。 使用letconst 。 使用添加到该语言的新功能。 不要使用供应商前缀。 从您的网站中删除该IE polyfill废话。 删除XHTML <!CDATA[[...废话,也废话了–我们在2014年改用HTML5。]每个人越早撤回对那些旧的/深奥的浏览器的支持,浏览器供应商实际上就越早遵循Web标准并接受新技术,因此我们可以尽快进入更安全的网络。


#2楼

像这样:

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

对于任何有兴趣阅读更多内容的人,Stack Overflow用户kangax都写了一篇非常深入的博客文章,关于其博客上的delete语句,“ 了解删除” 。 强烈建议。


#3楼

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

这适用于Firefox和Internet Explorer,我认为它适用于所有其他产品。


#4楼

您在问题标题中使用的术语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语句将阻止删除创建的对象。

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

delete regex; //False

结果将为false ,这意味着您的delete语句未按预期执行。 但是,如果您以前没有创建过该变量,而仅使用myOtherObject["regex"]作为最后一个现有引用,则可以通过删除它来完成此操作,例如:

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

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


更新:感谢@AgentME:

在删除属性之前将属性设置为null不会完成任何操作(除非该对象已由Object.seal密封并且删除失败。除非您特别尝试,否则通常情况并非如此)。

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


#5楼

操作员delete异常缓慢!

基准

删除是删除对象属性而没有任何剩余物的唯一正确方法,但与“替代”设置object[key] = undefined相比,它的工作速度要慢约100倍

此替代方法不是此问题的正确答案! 但是,如果谨慎使用它,则可以大大加快某些算法的速度。 如果您正在使用delete in循环,并且在性能方面遇到问题,请阅读详细说明。

什么时候应该使用delete和何时将值设置为undefined

一个对象可以看作是一组键值对。 我所说的“值”是连接到该“键”的原始对象或对其他对象的引用。

当将结果对象传递给您无法控制的代码时(或者不确定您的团队或您自己时) ,请使用delete

从哈希图中删除密钥

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

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

键保留在哈希图中的位置 ,仅将值替换为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] = undefineddelete obj[prop]快,但另一个重要的考虑因素是obj[prop] = undefined可能并不总是合适的。 delete obj[prop]obj删除prop并从内存中删除它,而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个插槽将仅设置为undefined,这会使它们挂在内存中。 继续,尝试在控制台中运行以上代码并亲自查看。 强制执行内存不足错误后,请尝试再次运行它,但以下版本的代码使用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

但是,多态数组存在两个无法解决的主要问题:

  1. 它们速度慢且内存效率低下。 当访问特定的索引时,浏览器不仅要获取数组的全局类型,还必须基于每个索引来获取类型,从而每个索引都存储该类型的其他元数据。
  2. 一旦是多态的,总是多态的。 将数组设为多态时,无法在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可以。 因此,应该始终尽可能地为其对象使用相应的类型,以免偶然导致多态。 一个这样的人可以使用以下列表作为一般参考,以帮助他们前进。 但是,请不要明确使用以下想法。 相反,请使用适用于您的代码的任何方法。

  • 当使用类型为布尔基元的数组/变量时,请使用falseundefined作为空值。 虽然最好避免不必要的多态,但是重写所有代码以明确禁止它可能实际上会导致性能下降。 使用共同的判断!
  • 使用类型为数字基元的数组/变量时,请使用0作为空值。 请注意,内部有两种类型的数字:快速整数(包括2147483647至-2147483648)和慢速浮点双打(除NaNInfinity之外的任何数字)。 将整数降级为双精度数时,不能将其提升回整数。
  • 当使用类型为字符串基元的数组/变量时,请使用""作为空值。
  • 使用符号时,请等待,为什么要使用符号?!?! 符号对性能不利。 可以将所有编程为使用符号的程序重新编程为不使用符号,从而可以使没有符号的代码更快。 符号实际上只是超级无效的糖。
  • 使用其他任何东西时,请使用null

但是,请注意! 现在不要突然开始使用所有预先存在的代码执行此操作,因为这很可能会破坏此类预先存在的代码和/或引入奇怪的错误。 而是需要从一开始就实施这种有效的做法,并且在转换现有代码时,建议您对所有与之相关的行进行两次,三次,四次检查,因为尝试将旧代码升级为这种新做法可能是冒险,因为它是有益的。


#6楼

另一种选择是使用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()


#7楼

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

例如

var obj = {"property":"value", "property2":"value"};

if (obj && obj.hasOwnProperty("property2")) {
  delete obj.property2;
} else {
  //error handling
}

由于JavaScript的动态特性,在很多情况下,您根本不知道该属性是否存在。 检查obj是否在&&之前是否存在,还可以确保您不会因未定义对象上调用hasOwnProperty()函数而引发错误。

抱歉,这没有添加到您的特定用例中,但是我相信这是在管理对象及其属性时可以适应的一个很好的设计。


#8楼

这篇文章很老,我发现它很有帮助,所以我决定分享我写的unset函数,以防其他人看到这篇文章,并思考为什么它不像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"}

#9楼

删除运算符是最好的方法。

一个实时示例显示:

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

#10楼

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函数(以及delete运算符 )将返回false 。 如果property是可配置的,则即使property不存在,它也会返回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

#11楼

我个人使用Underscore.jsLodash的对象和数组操作:

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

#12楼

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

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

如果您不知道索引,则还必须进行索引搜索:

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

注意

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

因此,在从对象中删除值时,请始终首先考虑您是在处理对象属性还是在处理数组值,然后基于此选择适当的策略。

如果要尝试此操作,可以使用此Fiddle作为起点。


#13楼

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

例如:

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

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

delete obj.key1

或者,您也可以使用类似数组的符号:

delete obj[key1]

参考: MDN


#14楼

如果要删除深深嵌套在对象中的属性,则可以使用以下递归函数,并将该属性的路径作为第二个参数:

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: {}}}

#15楼

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

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


#16楼

老问题,现代答案。 使用对象分解( 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);

#17楼

使用ramda#dissoc,您将获得一个不带regex属性的新对象:

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

您还可以使用其他功能达到相同的效果-省略,选择,...


#18楼

另一种解决方案,使用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); 


#19楼

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

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

delete运算符从对象中删除给定的属性。 成功删除后,它将返回true,否则将返回false。 但是,重要的是要考虑以下情形:

  • 如果您要删除的属性不存在,则删除将没有任何效果,并且将返回true

  • 如果对象的原型链上存在相同名称的属性,则删除后,该对象将使用原型链中的属性(换句话说,删除仅会影响其自身的属性)。

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

  • 因此,delete不能删除全局范围内的任何函数(无论这是函数定义还是函数(表达式)的一部分)。

  • 作为对象一部分的功能(除了
    全局范围)可以通过delete删除。

  • 用let或const声明的任何属性都不能从定义它们的范围中删除。 不可配置的属性无法删除。 这包括诸如Math,Array,Object之类的内置对象的属性,以及使用Object.defineProperty()之类的方法不可配置创建的属性。

以下代码段给出了另一个简单的示例:

 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/zh-CN/docs/Web/JavaScript/Reference/Operators/delete


#20楼

尝试这个

delete myObject['key'];

#21楼

您好,您可以尝试这种简单的排序

var obj = [];

obj.key1 = {name: "John", room: 1234};
obj.key2 = {name: "Jim", room: 1234};

delete(obj.key1);

#22楼

丹的断言“删除”非常缓慢,他发布的基准测试受到质疑。 因此,我自己在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

请注意,我有意在一个循环中执行了多个“删除”操作,以最大程度地减少其他操作引起的影响。


#23楼

使用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}

#24楼

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"]; } } ); 


#25楼

考虑创建没有"regex"属性的新对象,因为原始对象始终可以被程序的其他部分引用。 因此,您应该避免对其进行操作。

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


#26楼

JavaScript中的属性移除

此页面上提供了许多不同的选项,不是因为大多数选项是错误的,或者不是答案是重复的,而是因为适当的技术取决于您所处的情况以及您和/或您的任务目标团队正在努力实现。 要明确回答您的问题,您需要知道:

  1. 您要定位的ECMAScript版本
  2. 您要删除其属性的对象类型范围以及需要省略的属性名称类型(仅字符串?符号?从任意对象映射的引用弱?这些年来,JavaScript都是属性指针的类型)
  3. 您和您的团队使用的编程精神/模式。 您是否偏爱功能性方法,并且团队中的突变是根深蒂固的,还是您采用了狂野西部突变的面向对象技术?
  4. 您是要使用纯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"

#27楼

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


#28楼

使用ES6:

(解构+传播运算符)

const myObject = {
    regex: "^http://.*",
    b: 2,
    c: 3
};
const { regex, ...noRegex } = myObject;
console.log(noRegex); // => { b: 2, c: 3 }

#29楼

传播语法 (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];


重新分配
delete快2倍以上,但是不会删除该属性,并且可以对其进行迭代。

obj[key] = null;
obj[key] = false;
obj[key] = undefined;


点差算子
ES6运算符使我们可以返回一个全新的对象(不包括任何属性),而无需更改现有对象。 不利的一面是,它的性能比上述更差,因此当您需要一次删除许多属性时,建议不要使用它。

{ [key]: val, ...rest } = obj;

#30楼

您可以将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://.*" }

#31楼

克隆没有属性的对象:

例如:

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 }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值