提问



假设我创建一个对象如下:


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出乎意料地慢了!



看看基准[172]


删除是删除对象属性而没有任何剩余物的唯一真正方法,但它可以 ~100倍慢
与其替代相比,设定object[key] = undefined


这个替代方案不是这个问题的正确答案!但是,如果你小心使用它,你可以大大加快一些算法。如果您在循环中使用delete并且遇到性能问题,请阅读详细说明。


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



对象可以被视为一组键值对。我称之为值的是一个原语或对其他对象的引用,连接到该键。


当您将结果对象传递给您无法控制的代码(或者您不确定您的团队或您自己)时,请使用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] = undefineddelete obj[prop]更快,但另一个重要的考虑因素是obj[prop] = undefined可能并不总是合适的。 delete obj[prop]obj中删除prop并从记忆中删除它,而obj[prop] = undefined只是将prop的值设置为undefined,留下obj]]仍在记忆中。因此,在创建和删除许多密钥的情况下,使用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


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



  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之外的任何其他数字)。当一个整数降级为double时,它不能被提升回整数。

  • 使用键入字符串原语的数组/变量时,请使用""作为空值。

  • 使用符号时,请等待,为什么使用符号?!?!符号是表现糟糕的juju。编程为使用符号的所有内容都可以重新编程为不使用符号,从而产生没有符号的更快代码。符号实际上只是超低效的元糖。

  • 使用其他任何内容时,请使用null



但是,要小心!现在不要突然开始使用所有预先存在的代码执行此操作,因为它可能会破坏此类预先存在的代码和/或引入奇怪的错误。相反,这种有效的实践需要从一开始就实现,并且当转换预先存在的代码时,建议您对所有与之相关的行进行双倍,三倍,四倍检查,因为尝试将旧代码升级到此新实践可以是有风险,因为它是有益的。

其它参考1




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

console.log ( myObject.regex); // logs: undefined



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


在数组中,与普通旧对象不同,使用deletenull的形式留下垃圾,在数组中创建洞。


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


正如您所看到的,delete并不总是按照人们的预期工作。值被覆盖,但内存未重新分配。


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


例如,假设您正在创建一个webapp,它使用JSON序列化来存储用于字符串中tabs的数组(在本例中为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问题,你仍然要取悦 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先生感到高兴。万岁!(我还是告诉他,不过......)

其它参考2


老问题,现代答案。使用对象解构,ECMAScript  6功能,它很简单:[174]


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试用编辑器中看到它的实际效果。[175]








要重新分配到同一个变量,请使用let:


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

其它参考3


另一种方法是使用Underscore.js库。 [176]


请注意,_.pick()_.omit()都返回对象的副本,而不是直接修改原始对象。将结果分配给原始对象应该可以解决问题(未显示)。


参考:link _。pick(object,* keys) [177]


返回对象的副本,过滤到只有值的值
列入白名单的密钥(或有效密钥数组)。


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

_.pick(myJSONObject, "ircEvent", "method");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};


参考:link _。omit(object,* keys) [178]


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


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

_.omit(myJSONObject, "regex");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};


对于阵列,_.filter()_.reject()可以以类似的方式使用。

其它参考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,这意味着您的删除语句没有按预期执行。但如果您之前没有创建该变量,并且您只有myOtherObject["regex"]作为最后一个现有引用,你可以通过删除它来完成这个:


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


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





更新
感谢@AgentME:



  在删除它之前将属性设置为null不会完成
  任何东西(除非对象已被Object.seal和
  删除失败。除非你具体,否则通常情况并非如此
  尝试)。



要获得Object.seal的更多信息:Object.seal()[179]

其它参考5


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


Reflect.deleteProperty(myJSONObject, 'regex');


这相当于:


delete myJSONObject['regex'];


但是如果对象的属性不可配置,则无法使用deleteProperty函数或删除运算符删除它:


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,即使属性不存在。[[[182] [183]​​]]


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

其它参考6


假设您有一个如下所示的对象:


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也会搞砸你的索引。


因此,在从对象中删除值时,始终首先考虑您是在处理对象属性还是处理数组值,并根据它选择适当的策略。


如果你想试验这个,你可以用这个小提琴作为起点。[184]

其它参考7


删除操作符是最好的方法。[185]


一个实例来展示:


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

其它参考8


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


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

其它参考9


这篇文章非常陈旧,我发现它非常有用,所以我决定分享我写的未设置的函数,以防其他人看到这篇文章,并想想为什么它不像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"}

其它参考10


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


例如


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

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


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


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

其它参考11


另一种解决方案,使用 Array#reduce [187]




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



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


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



  delete运算符从对象中删除给定属性。上
  成功删除,它将返回true,否则将返回false。
  但是,请务必考虑以下情况:

  
  

      
  • 如果您要删除的媒体资源不存在,请删除
      不会有任何影响,并将返回true

  •   
  • 如果对象的原型上存在具有相同名称的属性
      链,然后,删除后,该对象将使用该属性
      原型链(换句话说,删除只对自己产生影响
      属性)。

  •   
  • 无法从全局范围中删除使用var声明的任何属性
      或者来自功能范围。

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

  •   
  • 作为对象一部分的函数(除了

      全局范围)可以删除删除。

  •   
  • 使用let或const声明的任何属性都不能从定义它们的作用域中删除。无法删除不可配置的属性。这包括内置对象的属性,如Math,Array,Object和属性,这些属性是使用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



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


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

其它参考12


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




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

myObject.regex = undefined;
myObject = JSON.parse(JSON.stringify(myObject));

console.log(myObject);



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


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


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

其它参考13


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


例如:


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


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


delete obj.key1


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


delete obj[key1]


参考:MDN。[189]

其它参考14


丹的断言删除非常慢,他发布的基准测试结果令人怀疑。所以我自己在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


注意,我有意在一个循环周期中执行多个删除操作,以最小化其他操作引起的影响。

其它参考15


考虑创建一个没有"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"];
        }
    }
);



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,除了第一个版本。但是,它的变异违反了某些编程原则并且具有性能影响。当在严格模式下用于不可配置的属性时,它也可能导致未捕获的异常。[190]


基于休息的字符串属性遗漏



当需要非变异方法并且您不需要考虑符号键时,此类别用于在较新的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"

其它参考16


尝试这个


delete myObject['key'];

其它参考17


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


var obj = [];

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

delete(obj.key1);

其它参考18




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

const { regex, ...other } = myObject;

console.log(myObject)
console.log(regex)
console.log(other)



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

其它参考19


您可以使用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将会删除,或者如果处于严格模式,则会抛出错误。

其它参考20


@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 }

其它参考21


很简单:


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

delete myObject.regex;