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




object.keys (24)

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

例如

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

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

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

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

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

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

删除属性regex以最终使用新的myObject的最佳方法是什么,如下所示?

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

试试这个

delete myObject['key'];

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


非常简单:

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

delete myObject.regex;

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

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

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


丹的断言“删除”非常缓慢,而他发布的基准则受到怀疑。所以我在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

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


更新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语言,所以一切都是对象,包括数组 。 因此,我认为有必要指出一个特别的警告。

在数组中,与普通旧对象不同,使用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的真正原因是因为留下垃圾填充和混乱的数据结构是草率和容易出错的。

接下来是一个非常冗长的人为场景,所以如果你愿意,你可以跳到“解决方案”这一部分。 我离开这一部分的唯一原因是因为我认为有些人可能认为这很有趣,而且我不想成为那个发布“有趣”答案然后从中删除所有“有趣”的“那个人”。 。

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

设计和冗长的PDP-11场景

例如,假设您正在创建一个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.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,则将切片后的整个数组n = array.length - startn = 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() )。 我发现这一点,同时想看看是否有一个问题要求从对象中告诉数组,看看是否有比我更好的解决方案,或者如果没有,则添加我的。 因此,如果您使用的是早于ECMA 5的JavaScript版本,那么就是您的polyfill。 但是,我强烈建议不要使用我的is_array()函数,因为继续支持旧版本的JavaScript意味着继续支持实现它们的旧浏览器,这意味着鼓励使用不安全的软件并使用户面临恶意软件的风险。 所以请使用Array.isArray() 。 使用letconst 。 使用添加到语言中的新功能。 不要使用供应商前缀。 从您的网站删除 IE polyfill废话。 删除那个XHTML <!CDATA[[...废话 - 我们在2014年转移到HTML5。每个人越早撤回对那些旧/深奥浏览器的支持,浏览器供应商越早实际遵循Web标准并拥抱新技术,我们越早进入更安全的网络。


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

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: '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

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

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…


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

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

操作员delete意外慢!

看看benchmark

删除是删除对象属性而没有任何剩余物的唯一真正方法,但与其“替代”相比,它的工作速度要慢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 ,它将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

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

  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

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


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

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

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

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


您在问题标题中使用的术语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()



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


像这样:

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声明的非常深入的博客文章, 了解删除 。 强烈推荐。


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

例如:

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

要删除任何属性,请key1使用以下delete关键字:

delete obj.key1

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

delete obj[key1]

参考:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…


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。然而,它的变异违反了一些编程原则并具有性能影响。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…上使用时,它也可能导致未捕获的异常。

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

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

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

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 }

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

var obj = [];

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

delete(obj.key1);

使用ramda#dissoc你将获得一个没有属性的新对象regex

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

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


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

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函数(以及developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…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




object-properties