代码之家  ›  专栏  ›  技术社区  ›  johnstok

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

  •  5341
  • johnstok  · 技术社区  · 17 年前

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

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

    移除财产的最好方法是什么 regex 以新的结束 myObject 如下?

    var myObject = {
        "ircEvent": "PRIVMSG",
        "method": "newURI"
    };
    
    36 回复  |  直到 7 年前
        1
  •  7373
  •   Jonathan stijn.aerts    8 年前

    这样地:

    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 在他们的博客上发表声明, Understanding delete . 强烈推荐。

        2
  •  777
  •   Community Mohan Dere    8 年前

    算符 delete 真是太慢了!

    看看 benchmark .

    删除是删除对象属性的唯一真正方法,没有任何残留,但它可以工作 大约慢100倍 , 与其“备选方案”相比,设置 object[key] = undefined .

    这个备选方案不是这个问题的正确答案!但是,如果你小心使用它,你可以大大加快一些算法的速度。如果您正在使用 删除 在循环中,如果性能有问题,请阅读详细的解释。

    什么时候用 删除 当设定值为 undefined ?

    对象可以看作是一组键值对。我所称的“值”是一个基元或对其他对象的引用,连接到该“键”。

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

    它 从哈希图中删除键 .

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

    使用设置到 未定义 , 当你关心表演的时候。它可以给您的代码带来很大的帮助。

    这个 密钥保留在哈希图中的位置上 ,仅将值替换为 未定义 . 明白,那 for..in 循环仍将迭代该键。

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

    使用这种方法,不是全部 ways of determining property existence 将按预期工作。

    但是,此代码:

    object.field === undefined

    两种方法的行为相同。

    测验

    总的来说,区别在于决定财产存在的方式,以及 在…中 循环。

     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]=未定义 可能并不总是合适的。 删除对象[属性] 移除 prop 从 obj 把它从记忆中抹去, obj[prop]=未定义 只需设置 支柱 到 未定义 哪片叶子 支柱 仍在记忆中。因此,在创建和删除许多键的情况下,使用 obj[prop]=未定义 可能会强制昂贵的内存调节(导致页面冻结)并可能导致内存不足错误。检查以下代码。

    "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个插槽将仅设置为“未定义”,这会使它们挂在内存中。继续,尝试在控制台中运行上述代码并亲自查看。在强制执行内存不足错误后,尝试再次运行它,除非使用以下版本的代码 删除 而不是操作员。

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

    如上面的代码片段所示,对于 删除 操作员。不过,不要太担心这个问题。这只会成为长寿命对象的一个问题,这些对象会不断添加新的关键点。在任何其他情况下(这几乎是现实编程中的每一种情况),最适合使用 obj[prop]=未定义 . 本节的主要目的只是让您注意到这一点,以便在极少数情况下,这在您的代码中成为一个问题,那么您可以更容易地理解问题,从而不必浪费时间来分析代码来定位和理解这个问题。

    不要总是设置为 未定义

    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浏览器中多态性不能撤消。因此,即使将多态数组恢复为非多态数组,浏览器仍然会将其存储为多态数组。

    人们可以把多态性比作药物成瘾。乍一看,它似乎利润丰厚:漂亮的、毛绒绒绒的代码。然后,编码人员将他们的阵列引入多态性药物。立刻,多态数组的效率就降低了,而且由于被下药,它再也不能像以前那样有效了。为了将这种情况与现实生活联系起来,吸食可卡因的人甚至可能无法操作一个简单的门把手,更不用说能够计算圆周率的数字了。同样,多态性药物的阵列也不能像单态阵列那样有效。

    但是,毒品旅行的类比与 删除 手术?答案包含在上面代码片段的最后一行代码中。因此,让我们重新检查一下,这次要扭转一下。

    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 或 未定义 作为空值。虽然避免不必要的多态性是很好的,但是重写所有代码以明确地禁止它实际上可能会导致性能下降。使用共同的判断!
    • 使用类型化为数字原语的数组/变量时,请使用 0 作为空值。注意,在内部,有两种类型的数字:快速整数(2147483647到-2147483648包括在内)和慢速浮点双精度(除此之外的任何数字包括 NaN 和 Infinity )当一个整数降级为double时,它将无法提升回整数。
    • 使用类型化为字符串原语的数组/变量时,请使用 "" 作为空值。
    • 使用符号时,等等,为什么要使用符号????!符号对性能不好。所有编程为使用符号的东西都可以重新编程为不使用符号,从而在没有符号的情况下产生更快的代码。符号实际上只是超低效的元糖。
    • 当使用其他东西时,使用 null .

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

        3
  •  215
  •   str    8 年前

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

    这在Firefox和Internet Explorer中有效,我认为它在所有其他浏览器中都有效。

        4
  •  165
  •   Braden Best    8 年前

    更新2018-07-21: 很长一段时间以来,我对这个答案感到很尴尬,所以我想是时候把它润色一下了。只是一些评论、澄清和格式化,以帮助加快阅读这个答案中不必要的冗长和复杂部分。


    简短的版本

    问题的实际答案

    正如其他人所说,你可以使用 delete .

    obj // {"foo": "bar"}
    delete obj["foo"]
    obj // {}
    obj["foo"] // undefined
    

    数组等效

    不要 删除 从数组中。使用 Array.prototype.splice 相反。

    arr // [1,2,3,4,5]
    arr.splice(3,1); // 4
    arr // [1,2,3,5]
    

    长版

    javascript是一种OOP语言,所以一切都是一个对象,包括 数组 . 因此,我觉得有必要指出一个特别的警告。

    在数组中,使用 删除 以垃圾的形式留在垃圾后面 null ,在数组中创建一个“孔”。

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

    正如你所看到的, 删除 并非总是如人们所料。该值将被覆盖,但不会重新分配内存。这就是说, array[4] 没有迁移到 array[3] . 这与 Array.prototype.unshift ,它在数组的开头插入一个元素并向上移动所有内容( array[0] 变成 array[1] 等)

    老实说,除了 无效的 而不是 undefined --这确实很奇怪——这种行为 不应该 令人惊讶,因为 删除 是一元运算符,比如 typeof 这是一种很难理解的语言,不应该关心 类型 它所使用的对象,而 Array 是的子类 Object 用方法 专门为 使用数组。所以没有充分的理由 删除 准备一个特殊的案例来重新移动阵列,因为这样做只会让不必要的工作放慢速度。回想起来,我的期望是不现实的。

    当然,它 做 让我吃惊。因为我写这篇文章是为了证明我反对“空垃圾”的运动是正当的:

    忽略内在的危险和问题 无效的 以及浪费的空间,如果数组需要精确的话,这可能是有问题的。

    这是摆脱 无效的 S—— 无效的 只有使用不当才有危险,与“精度”无关。你不应该这样做的真正原因 删除 从一个数组中删除是因为将垃圾填充和杂乱的数据结构放在周围是草率的和容易出错的。

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

    …我知道这很愚蠢。

    精心设计和长篇大论的PDP-11方案

    例如,假设您正在创建一个webapp,它使用json序列化将用于“tabs”的数组存储在字符串中(在本例中, localStorage )我们还可以说,当绘制到屏幕上时,代码使用数组成员的数字索引来“命名”它们。为什么要这样做而不仅仅是存储“标题”?因为… 原因 .

    好吧,我们假设你正试图根据这个请求保存内存 一 从20世纪60年代运行的Unix运行一台PDP-11小型计算机,并编写了自己的基于电子链接的、符合javascript的、行打印机友好的浏览器的用户,因为x11 毫无疑问 .

    除了越来越愚蠢的边缘情况,使用 删除 在所述阵列上将导致 无效的 污染阵列,并可能导致应用程序中的错误。如果你查一下 无效的 ,它将直接向上跳过数字,从而使选项卡呈现为 [1] [2] [4] [5] ... .

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

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

    现在,你 能够 保留第二个迭代器,比如 j ,仅当从数组中读取有效值时递增。但这并不能完全解决 无效的 问题,你还是要取悦它 拖钓 PDP11用户。唉,他的电脑 不 有足够的内存来保存最后一个整数 (不要问他如何处理可变宽度数组…) .

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

    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.拼接

    幸运的是,数组 做 具有删除索引和重新分配内存的专用方法: 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与array.prototype.slice

    我觉得指出这两个同名函数之间的区别很重要,因为它们都非常有用。

    数组.原型.拼接(开始,n)

    .splice() 改变数组,并返回删除的索引。从索引开始对数组进行切片, start 和 n 元素被切掉。如果未指定n,则后面的整个数组 开始 被切掉了( 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() 是非破坏性的,并返回包含指定索引的新数组 开始 到 end . 如果 结束 未指定,行为与 剪接() ( end = array.length )这种行为有点棘手,因为出于某种原因, 结束 索引来自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
    

    指定的索引 结束 只是从切片中排除。带圆括号的索引表示被切片的内容。无论哪种方式,行为都不是直观的,并且它必然会因一个错误而导致公平的分享,因此您可能会发现让包装函数更接近地模拟 剪接() :

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

    注意,包装器函数被设计为对类型非常严格,并且将返回 无效的 如果有什么东西掉了。包括把一根绳子 "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。但是,我强烈建议不要使用 ISSARARY() 功能,因为继续支持旧版本的javascript意味着继续支持实现它们的旧浏览器,这意味着鼓励使用不安全的软件,并使用户面临恶意软件的风险。所以请使用 数组,数组() . 使用 let 和 const . 使用添加到语言中的新功能。 不要 使用供应商前缀。 删除 你网站上的那篇文章。删除XHTML <!CDATA[[... 废话,我们在2014年搬到了HTML5。每个人越早撤销对那些老的/深奥的浏览器的支持,浏览器供应商就越快能够真正遵循Web标准并采用新技术,我们就越快能够转向更安全的Web。

        5
  •  129
  •   Koen.    9 年前

    旧问题,现代答案。使用对象销毁,一个 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);
    

    You can see it in action in the Babel try-out editor.


    编辑:

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

    let myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
    ({ regex, ...myObject } = myObject);
    console.log(myObject);
    
        6
  •  81
  •   Thaddeus Albers    8 年前

    另一种选择是使用 Underscore.js 图书馆。

    注意 _.pick() 和 _.omit() 两者都返回对象的副本,并且不直接修改原始对象。将结果分配给原始对象应该可以实现这个技巧(未显示)。

    参考文献: link _.pick(对象,*键)

    返回对象的副本,筛选后仅具有 白名单键(或有效键数组)。

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

    参考文献: link _.omit(对象,*键)

    返回对象的副本,过滤后省略 黑名单密钥(或密钥数组)。

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

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

        7
  •  42
  •   Mehran Hatami    11 年前

    您在题名中使用的术语 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"]
    

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

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

    这里的另一个重要点是要注意您对同一对象的其他引用。例如,如果创建如下变量:

    var regex = myJSONObject["regex"];
    

    或将其作为新指针添加到其他对象,如:

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

    即使你把它从你的物体上移开 myJSONObject ,该特定对象不会从内存中删除,因为 regex 变量和 myOtherObject["regex"] 还有他们的价值观。那么,我们如何从内存中删除对象呢?

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

    这意味着在这种情况下,您将无法删除该对象,因为您已经创建了 正则表达式 变量通过 var 声明,如果您这样做:

    delete regex; //False
    

    结果是 false ,这意味着您的DELETE语句没有按预期执行。但是如果你以前没有创建过这个变量,你只有 myotherobject[“regex”] 作为最后一个现有引用,您可以通过如下方式删除它来完成此操作:

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

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


    更新: 感谢@agentme:

    在删除前将属性设置为空并不能完成 任何东西(除非物体已被object.seal和 删除失败。通常情况下不是这样,除非你特别 试试看)。

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

        8
  •  33
  •   John Slegers    9 年前

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

    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 后来。换言之, 删除 将移除元素,但它不会更新 length 财产。使用 删除 也会破坏你的索引。

    因此,当从一个对象中删除值时,首先要考虑是处理对象属性还是处理数组值,并基于此选择适当的策略。

    如果你想试验这个,你可以使用 this Fiddle 作为起点。

        9
  •  32
  •   madox2    10 年前

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

    Reflect.deleteProperty(myJSONObject, 'regex');
    

    相当于:

    delete myJSONObject['regex'];
    

    但是,如果对象的属性不可配置,则既不能使用delete property函数也不能使用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 operator 返回 false 当试图删除它的任何属性时。如果属性是可配置的,则返回 true ,即使属性不存在。

    两者之间的区别 delete 和 删除属性 使用严格模式时:

    "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
    
        10
  •  31
  •   Lior Elrom    7 年前

    Spread Syntax (ES6)

    给任何需要它的人…

    若要在此线程中完成@koen answer,如果要使用排列语法删除动态变量,可以这样做:

    const key = 'a';
    
    const { [key]: foo, ...rest } = { a: 1, b: 2, c: 3 };
    
    console.log(rest); // { b: 2, c: 3 }
    

    * foo 将是一个新变量,其值为 a (1)。


    更新 :
    从对象中删除属性的常见方法很少。
    每个人都有自己的利弊( check this performance comparison ):

    Delete Operator
    但是,如果您在大量对象上操作,因为它的性能没有得到优化,那么它可能不是最佳选择。

    delete obj[key];
    


    Reassignment
    比 delete 但是,物业 不 已删除并可重复。

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


    Spread Operator
    这个 ES6 运算符允许我们返回一个全新的对象,不包括任何属性,而不改变现有对象。缺点是,它的性能比上面提到的差,当您一次需要删除许多属性时,不建议使用它。

    { [key]: val, ...rest } = obj;
    
        11
  •  25
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    这个 delete operator 是最好的方法。

    要显示的实时示例:

    var foo = {bar: 'bar'};
    delete foo.bar;
    console.log('bar' in foo); // Logs false, because bar was deleted from foo.
    
        12
  •  23
  •   emil    7 年前

    我个人使用 Underscore.js 或 Lodash 对于对象和数组操作:

    myObject = _.omit(myObject, 'regex');
    
        13
  •  18
  •   kind user Faly    8 年前

    另一个解决方案,使用 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);
        14
  •  18
  •   Alireza    8 年前

    使用 删除 方法是实现这一点的最佳方法,根据MDN描述,“删除”运算符从对象中移除属性。所以你可以简单地写:

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

    删除运算符从对象中删除给定的属性。论 删除成功,返回真,否则返回假。 但是,必须考虑以下情况:

    • 如果要删除的属性不存在,请删除 不会有任何影响,将返回真

    • 如果对象原型上存在同名属性 然后,在删除后,对象将使用 原型链(换句话说,删除仅对自身有影响 属性)。

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

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

    • 作为对象一部分的函数(除了
      全局范围)可以用delete删除。

    • 用let或const声明的任何属性都不能从定义它们的作用域中删除。无法删除不可配置的属性。这包括内置对象(如数学、数组、对象)的属性,以及使用诸如object.defineproperty()等方法创建为不可配置的属性。

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

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

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

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

        15
  •  17
  •   Peter Mortensen Pieter Jan Bonestroo    9 年前

    这篇文章非常古老,我觉得它非常有用,所以我决定分享我写的unset函数,以防其他人看到这篇文章,并思考为什么它不像php unset函数那么简单。

    写这个新的原因 unset 函数的作用是保留哈希图中所有其他变量的索引。看看下面的例子,看看从散列图中删除一个值后,“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"}
    
        16
  •  16
  •   Willem    12 年前

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

    例如

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

    由于javascript的动态特性,通常情况下您根本不知道属性是否存在。在&&之前检查obj是否存在,并确保不会由于对未定义对象调用hasownproperty()函数而引发错误。

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

        17
  •  12
  •   Amio.io    9 年前

    使用 ramda#dissoc 您将得到一个没有该属性的新对象 regex :

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

    您还可以使用其他函数来实现相同的效果-省略、选取…

        18
  •  11
  •   ayushgp    10 年前

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

    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: {}}}
    
        19
  •  11
  •   Peter Mortensen Pieter Jan Bonestroo    9 年前

    尝试以下方法。指派 Object 属性值到 undefined . 然后 stringify 客体与 parse .

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

    使用ES6:

    (破坏+扩展运算符)

        const myObject = {
          regex: "^http://.*",
          b: 2,
          c: 3
        };
        const { regex, ...noRegex } = myObject;
        console.log(noRegex); // => { b: 2, c: 3 }
    
        21
  •  7
  •   Peter Mortensen Pieter Jan Bonestroo    9 年前

    您可以使用 delete 关键字。

    例如:

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

    要移除任何属性,例如 key1 使用 删除 关键字如下:

    delete obj.key1
    

    也可以使用类似数组的符号:

    delete obj[key1]
    

    裁判: MDN .

        22
  •  6
  •   Chong Lip Phang    9 年前

    丹认为“删除”的速度非常慢,他发布的基准也受到了质疑。所以我自己在Chrome59中进行了测试。“删除”似乎慢了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
  •  6
  •   ideaboxer    8 年前

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

    const myObject = {
        "ircEvent": "PRIVMSG",
        "method": "newURI",
        "regex": "^http://.*"
    };
    
    const { regex, ...newMyObject } = myObject;
    
    console.log(newMyObject);
        24
  •  6
  •   xgqfrms-gildata    8 年前

    object.assign()对象.keys()数组.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
  •  5
  •   codemirror    9 年前

    试试这个

    delete myObject['key'];
    
        26
  •  5
  •   Gohel Dhaval    9 年前

    你好,你可以试试这个简单的

    var obj = [];
    
    obj.key1 = {name: "John", room: 1234};
    obj.key2 = {name: "Jim", room: 1234};
    
    delete(obj.key1);
    
        27
  •  5
  •   xiang    8 年前

    const myObject = {
            "ircEvent": "PRIVMSG",
            "method": "newURI",
            "regex": "^http://.*"
        };
    
    const { regex, ...other } = myObject;
    
    console.log(myObject)
    console.log(regex)
    console.log(other)
        28
  •  4
  •   johndavedecano    9 年前

    使用土灰

    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}
    
        29
  •  4
  •   james_womack    8 年前

    在javascript中删除属性

    这个页面上有许多不同的选项,不是因为大多数选项都是错误的,或者答案是重复的,而是因为适当的技术取决于你所处的环境以及你和/或你的团队试图完成的任务的目标。要明确回答你的问题,你需要知道:

    1. 你要瞄准的ecmascript版本
    2. 要删除其属性的对象类型的范围以及需要忽略的属性名称的类型(仅限字符串?符号?从任意对象映射的弱引用?多年来,这些都是JavaScript中的属性指针类型)
    3. 您和您的团队使用的编程方法/模式。你喜欢功能性的方法,而突变在你的团队中是用原话描述的,还是使用了WildWest的面向对象的突变技术?
    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。但是,它是可变的,违反了一些编程原则,并且具有性能影响。当用于 non-configurable properties in strict mode .

    基于REST的字符串属性省略

    此类别用于在需要非可变方法且不需要考虑符号键的情况下,以较新的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:'kidddd!',[符号.for('iscool')]:真
    const name,…coolio=foo//coolio没有“name”
    const iscool,…coolio2=foo//coolio2包含从“foo”开始的所有内容,因为“iscool”不解释符号:(
    

    基于库的属性省略

    此类别通常允许更大的功能灵活性,包括在一个语句中忽略符号和多个属性:

    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"
    
        30
  •  3
  •   hygull    8 年前

    约翰斯塔克 我们还可以使用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 }