javascript - property - js object




如何從JavaScript對像中刪除屬性? (20)

假設我創建一個對像如下:

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

刪除屬性regex以最終使用新的myObject的最佳方法是什麼,如下所示?

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

2(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)的新變量。


更新
從對像中刪除屬性的常用方法很少。
每個人都有自己的優點和缺點(檢查這個性能比較):

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
可讀且簡短,但如果您對大量對象進行操作,則可能不是最佳選擇,因為其性能未得到優化。

delete obj[key];


Reassignment
超過2倍delete,但該屬性不會被刪除,可以迭代。

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


Spread運算符
ES6運算符允許我們返回一個全新的對象,不包括任何屬性,而不會改變現有對象。缺點是它具有較差的性能,並且當您需要一次刪除許多屬性時不建議使用它。

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

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"

操作員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

但是,要小心! 現在不要突然開始使用所有預先存在的代碼執行此操作,因為它可能會破壞此類預先存在的代碼和/或引入奇怪的錯誤。 相反,這種有效的實踐需要從一開始就實現,並且當轉換預先存在的代碼時,建議您對所有與之相關的行進行雙倍,三倍,四倍檢查,因為嘗試將舊代碼升級到此新實踐可以是有風險,因為它是有益的。


更新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標準並擁抱新技術,我們越早進入更安全的網絡。


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

假設您有一個如下所示的對象:

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

因此,在從對像中刪除值時,始終首先考慮您是在處理對象屬性還是處理數組值,並根據它選擇適當的策略。

如果你想試驗這個,你可以用這個小提琴作為起點。


另一種方法是使用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 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: {}}}

您好,您可以嘗試這種簡單的排序

var obj = [];

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

delete(obj.key1);

老問題,現代答案。 使用對象解構, 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);

這篇文章非常陳舊,我發現它非常有用,所以我決定分享我寫的未設置的函數,以防其他人看到這篇文章並想想為什麼它不像PHP unset函數那麼簡單。

編寫這個新unset函數的原因是保留此hash_map中所有其他變量的索引。查看以下示例,並查看從hash_map中刪除值後“test2”的索引如何不更改。

function unset(unsetKey, unsetArr, resort){
  var tempArr = unsetArr;
  var unsetArr = {};
  delete tempArr[unsetKey];
  if(resort){
    j = -1;
  }
  for(i in tempArr){
    if(typeof(tempArr[i]) !== 'undefined'){
      if(resort){
        j++;
      }else{
        j = i;
      }
      unsetArr[j] = tempArr[i];
    }
  }
  return unsetArr;
}

var unsetArr = ['test','deletedString','test2'];

console.log(unset('1',unsetArr,true)); // output Object {0: "test", 1: "test2"}
console.log(unset('1',unsetArr,false)); // output Object {0: "test", 2: "test2"}

這裡有很多好的答案,但我只想說明當使用delete刪除JavaScript中的屬性時,首先檢查該屬性是否存在以防止錯誤通常是明智的。

例如

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

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

由於JavaScript的動態特性,通常情況下您根本不知道屬性是否存在。在&&之前檢查是否存在obj還確保由於在未定義的對像上調用hasOwnProperty()函數而不拋出錯誤。

很抱歉,如果這沒有添加到您的特定用例,但我相信這是一個很好的設計,以適應管理對象及其屬性。


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

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

這適用於Firefox和Internet Explorer,我認為它適用於所有其他人。


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

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

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


丹的斷言“刪除”非常緩慢,而他發布的基準則受到懷疑。所以我在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

請注意,我有意在一個循環週期中執行多個“刪除”操作,以最大限度地減少其他操作所造成的影響。


使用ramda#dissoc你將獲得一個沒有屬性的新對象regex

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

您還可以使用其他功能來實現相同的效果 - 省略,選擇,...


使用另一個解決方案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);


您可以使用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/…


考慮創建一個沒有"regex"屬性的新對象,因為原始對象總是可以被程序的其他部分引用。因此你應該避免操縱它。

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

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

console.log(newMyObject);






object-properties