Pytanie Jak usunąć właściwość z obiektu JavaScript?


Powiedzmy, że tworzę obiekt w następujący sposób:

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

Jaki jest najlepszy sposób na usunięcie nieruchomości regex skończyć z nowym myObject następująco?

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

4910
2017-10-16 10:57


pochodzenie


Znajdź tutaj benchmark, który porównuje "delete" vs "undefined" vs "null" jsben.ch/#/BWMiw - EscapeNetscape
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - titusfx


Odpowiedzi:


Lubię to:

delete myObject.regex;
// or,
delete myObject['regex'];
// or,
var prop = "regex";
delete myObject[prop];

Próbny

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

console.log(myObject);

Dla wszystkich zainteresowanych czytaniem więcej na ten temat, użytkownik Stack Overflow kangax napisał niewiarygodnie dogłębny post na blogu o delete oświadczenie na swoim blogu, Opis usuwania. Jest wysoce zalecane.


6839
2017-10-16 10:58



Sprawdzone, działa również z "delete myJSONObject ['regex'];" Widzieć: developer.mozilla.org/en/Core_JavaScript_1.5_Reference/... - johnstok
Wynik jednej z obserwacji w powyższym linku "zrozumienie usunięcia" jest taki, że ponieważ nie można koniecznie usunąć zmiennej, a jedynie właściwości obiektu, nie można usunąć właściwości obiektu "przez odniesienie" - var value = obj [ 'rekwizyt']; usuń wartość // nie działa - George Jempty
Więc tak naprawdę go nie usuwa? Po prostu staje się niezdefiniowany, ale klucz nadal istnieje? Czy czegoś brakuje? - Doug Molineux
@Potem nie, usuwa go. Dany: var x = {a : 'A', b : 'B'}; Porównać: delete x.a; typeof x.a; /* "undefined" */ x.hasOwnProperty('a'); /* false */ do x.b = undefined; typeof x.b; /* "undefined" */; x.hasOwnProperty('b'); /* true */ - nickf
@ ChristopherPfohl pracuje dla mnie. Tak jak powiedziałem, jest to dość dogłębne, więc trochę trudno podsumować. Podstawowa odpowiedź w powyższej odpowiedzi jest wystarczająca dla prawie wszystkich przypadków, blog przechodzi do bardziej zaawansowanych przypadków i powodów tych przypadków. - nickf


Operator delete jest nieoczekiwanie wolny!

Spójrz na reper.

Usuwanie jest jedynym prawdziwym sposobem usuwania właściwości obiektu bez żadnych resztek, ale działa ~ 100 razy wolniej, w porównaniu do jego "alternatywy", ustawienie object[key] = undefined.

Ta alternatywa nie jest poprawną odpowiedzią na to pytanie! Ale jeśli używasz go z ostrożnością, możesz znacznie przyspieszyć niektóre algorytmy. Jeśli używasz delete w pętlach i masz problemy z wydajnością, przeczytaj pełne wyjaśnienie.

Kiedy należy użyć delete a po ustawieniu wartości na undefined ?

Obiekt może być postrzegany jako zestaw par klucz-wartość. To, co nazywam "wartością", jest prymitywne lub odniesienie do innego obiektu, połączonego z tym "kluczem".

Posługiwać się delete, kiedy przekazujesz obiekt wynikowy do kodu, na którym nie masz kontroli (lub gdy nie jesteś pewien swojego zespołu lub siebie).

To usuwa klucz z hashmap.

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

Użyj ustawienia na undefined, kiedy dbasz o wydajność. Może to znacznie zwiększyć twój kod.

The klucz pozostaje na swoim miejscu w smyczy, tylko wartość jest zamieniana na undefined. Rozumiem to for..in pętla nadal będzie powtarzała ten klucz.

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

Korzystając z tej metody, nie wszystkie sposoby określania istnienia nieruchomości będzie działać zgodnie z oczekiwaniami.

Jednak ten kod:

object.field === undefined

będzie zachowywał się równoważnie dla obu metod.

Testy

Podsumowując, różnice dotyczą sposobów określania istnienia nieruchomości i około for..in pętla.

 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. *');

Uważaj na wycieki pamięci!

Podczas używania obj[prop] = undefined jest szybsze niż robienie delete obj[prop], kolejnym ważnym czynnikiem jest to obj[prop] = undefined nie zawsze są odpowiednie. delete obj[prop] usuwa prop od obj i usuwa go z pamięci, podczas gdy obj[prop] = undefined po prostu ustawia wartość prop do undefined który odchodzi prop wciąż w pamięci. Dlatego w sytuacji, gdy istnieje wiele kluczy, które są tworzone i usuwane, za pomocą obj[prop] = undefined może wymuszać kosztowne uzgadnianie pamięci (powodując zawieszenie się strony) i potencjalnie błąd braku pamięci. Sprawdź poniższy kod.

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

W powyższym kodzie, po prostu rób nodeRecords[i][lastTime] = undefined; spowoduje masową przeciekę pamięci, ponieważ każda klatka animacji. Każda klatka, wszystkie elementy DOM 65536 zajmą kolejne 65536 pojedynczych slotów, ale poprzednie 65536 będą ustawione tylko na niezdefiniowane, co spowoduje ich zawieszenie w pamięci. Śmiało, spróbuj uruchomić powyższy kod w konsoli i przekonaj się sam. Po wymuszeniu błędu braku pamięci spróbuj uruchomić go ponownie, z wyjątkiem poniższej wersji kodu korzystającego z deletezamiast tego operator.

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

Jak widać w powyższym fragmencie kodu, istnieje kilka rzadkich przypadków użycia tego pliku delete operator. Jednak nie przejmuj się zbytnio tym problemem. Stanie się to problemem tylko w przypadku obiektów o długiej żywotności, do których dodawane są stale nowe klucze. W każdym innym przypadku (co jest prawie w każdym przypadku w programowaniu w świecie rzeczywistym), jest najbardziej odpowiedni do użycia obj[prop] = undefined. Głównym celem tej sekcji jest zwrócenie na to uwagi, aby w rzadkich przypadkach stać się problemem w kodzie, dzięki czemu łatwiej zrozumiesz problem, a tym samym nie będziesz musiał tracić godzin na analizowanie kodu w celu zlokalizowania i rozumiem ten problem.

Nie zawsze ustawiaj undefined

Jednym z aspektów JavaScriptu, który należy wziąć pod uwagę, jest polimorfizm. Polimorfizm polega na przypisaniu tej samej zmiennej / gniazda w obiekcie różnych typów, jak pokazano poniżej.

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

Istnieją jednak dwa główne, nierozwiązywalne problemy z tablicami polimorficznymi:

  1. Są powolne, a pamięć nieefektywna. Podczas uzyskiwania dostępu do określonego indeksu, zamiast po prostu uzyskać globalny typ tablicy, przeglądarka musi zamiast tego pobrać typ na podstawie indeksu, przy czym każdy indeks przechowuje dodatkowe metadane tego typu.
  2. Raz polimorficzny, zawsze polimorficzny. Gdy tablica jest polimorficzna, polimorfizmu nie można cofnąć w przeglądarkach Webkit. Nawet jeśli przywrócisz tablicę polimorficzną do postaci nie-polimorficznej, będzie ona nadal przechowywana przez przeglądarkę jako tablica polimorficzna.

Polimorfizm można porównać do uzależnienia od narkotyków. Na pierwszy rzut oka wydaje się niezwykle lukratywny: ładny, bardzo puszysty kod. Następnie programista wprowadza swój zestaw do leku polimorfizmu. Natychmiast, polimorficzna tablica staje się mniej wydajna i nigdy nie może stać się tak wydajna jak przedtem, ponieważ jest odurzona. Aby skorelować taką sytuację z prawdziwym życiem, ktoś na kokainie może nie być nawet w stanie obsługiwać prostego klamki, a tym bardziej być w stanie wyliczyć cyfry PI. Podobnie, tablica na leku polimorfizmu nie może być tak wydajna jak macierz monomorficzna.

Ale w jaki sposób analogia dotycząca narkotyków odnosi się do delete operacja? Odpowiedź znajduje się w ostatnim wierszu kodu we fragmencie powyżej. Niech więc zostanie ponownie zbadany, tym razem z niespodzianką.

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

Przestrzegać. bar[1] = "" nie zmusza polimorfizmu, natomiast bar[1] = undefined robi. Dlatego zawsze należy, o ile to możliwe, stosować odpowiedni typ dla swoich obiektów, aby nie przypadkowo spowodować polimorfizm. Jedna taka osoba może użyć poniższej listy jako ogólnego odniesienia, aby je uruchomić. Nie należy jednak wyraźnie wykorzystywać poniższych pomysłów. Zamiast tego użyj tego, co działa dobrze dla twojego kodu.

  • Używając tablicy / zmiennej wpisanej do prymitywu boolowskiego, użyj albo false lub undefined jako pusta wartość. Chociaż unikanie niepotrzebnego polimorfizmu jest dobre, przepisanie całego kodu w celu wyraźnego zakazu będzie prawdopodobnie skutkować zmniejszeniem wydajności. Używaj wspólnej oceny!
  • Używając tablicy / zmiennej wpisanej do liczby podstawowej, użyj 0 jako pusta wartość. Zauważ, że wewnętrznie istnieją dwa rodzaje liczb: szybkie liczby całkowite (2147483647 do -2147483648 włącznie) i podwójne liczby powolne zmiennoprzecinkowe (wszystko inne, z wyjątkiem NaN i Infinity). Kiedy liczba całkowita jest obniżona do podwójnej, nie może być promowana z powrotem do liczby całkowitej.
  • W przypadku użycia tablicy / zmiennej wpisanej do pierwotnego ciągu znaków użyj "" jako pusta wartość.
  • Kiedy używasz Symbolu, czekaj, dlaczego używasz Symbolu?!?! Symbole są złe juju dla wydajności. Wszystko zaprogramowane do używania symboli można przeprogramować tak, aby nie używać symboli, co skutkuje szybszym kodem bez symboli. Symbole są po prostu super nieskutecznymi meta-cukrami.
  • Podczas korzystania z czegokolwiek innego użyj null.

Jednak bądź uważny! Nie rób tego nagle z całym istniejącym kodem, ponieważ prawdopodobnie zepsuje on istniejący kod i / lub wprowadzi dziwne błędy. Zamiast tego, taka efektywna praktyka musi być wdrożona od samego początku, a przy konwertowaniu istniejącego kodu zaleca się podwójne, potrójne, poczwórne sprawdzenie wszystkich linii odnoszących się do tego, ponieważ próba uaktualnienia starego kodu do tej nowej praktyki może być taka, ryzykowne, ponieważ jest satysfakcjonujące.


705
2018-02-12 17:48



właściwość jest przypisana do undefined nadal jest właściwością obiektu, więc nie zostanie usunięty przez GC, chyba że błędnie przeczytano ostatni akapit. - Lance
Myliłem się, dotykając tematu GC tutaj. Obie metody mają ten sam wynik dla GC: usuwają wartość powiązaną z kluczem. Jeśli ta wartość była ostatnim odniesieniem do jakiegoś innego obiektu, obiekt ten zostałby oczyszczony. - Dan
właściwość jest przypisana do niezdefiniowanej wciąż jest właściwością obiektu, więc nie zostanie usunięta przez GC GC nie zarządza niczym na temat właściwości. Gromadzi i usuwa wartości. Dopóki nic nie odwołuje się do wartości (obiektu, ciągu znaków itp.), GC usuwa ją z pamięci. - meandre
BTW, to jest podwójny problem, aby sprawdzić, czy właściwość istnieje w obiekcie JavaScript. Za pomocą w operator jest niezawodny, ale powolny. Sprawdź, czy właściwość nie jest niezdefiniowany "nie jest poprawną odpowiedzią", ale jest to szybszy sposób. czek - rdllopes
Czy ta odpowiedź jest nadal aktualna? jsperf jest obecnie wyłączony, ale ten benchmark Wydaje się wskazywać, że różnica prędkości wynosi zaledwie 25%, co nie ma miejsca blisko do "~ 100 razy wolniej" w tej odpowiedzi. - Cerbrus


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

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

Działa to w Firefoksie i Internet Explorerze i myślę, że działa we wszystkich innych.


193
2017-10-16 11:03



Czy istnieje sposób na usunięcie wielu właściwości z tej samej tablicy przy użyciu jednego wyrażenia - Aakriti.G
Czy przy próbie usunięcia wielu właściwości naraz lepiej nie zamieniać się na nowy obiekt? - jasonscript


Aktualizacja 2018-07-21: Przez długi czas czułem się zawstydzony tą odpowiedzią, więc myślę, że nadszedł czas, aby odrobinę ją dotknąć. Wystarczy krótki komentarz, wyjaśnienie i formatowanie, aby przyspieszyć czytanie niepotrzebnie długich i zawiłych części tej odpowiedzi.


KRÓTKA WERSJA

Właściwa odpowiedź na pytanie

Jak powiedzieli inni, możesz użyć delete.

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

Odpowiednik tablicy

Nie rób tego delete z tablicy. Posługiwać się Array.prototype.splice zamiast.

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

DŁUGA WERSJA

JavaScript jest językiem OOP, więc wszystko jest przedmiotem, w tym tablice. Dlatego uważam za konieczne wskazanie konkretnego zastrzeżenia.

W tablicach, w przeciwieństwie do zwykłych starych obiektów, używając delete pozostawia za sobą śmieci w postaci null, tworząc "dziurę" w tablicy.

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

Jak widzisz, delete nie zawsze działa tak, jak można by się spodziewać. Wartość zostanie nadpisana, ale pamięć nie zostanie ponownie przydzielona. To jest do powiedzenia, array[4] nie jest przenoszone do array[3]. Co jest przeciwieństwem Array.prototype.unshift, który wstawia element na początku tablicy i przesuwa wszystko w górę (array[0] staje się array[1]itp.)

Szczerze mówiąc, oprócz ustawienia na null zamiast undefined- co jest słusznie dziwne - to zachowanie nie powinien być zaskakujące, ponieważ delete jest jednoargumentowym operatorem, jak typeof, który jest ciężko gotowany na język i nie powinien dbać o to rodzaj obiektu, na którym jest używany, podczas gdy Array jest podklasą Object za pomocą metod specjalnie zaprojektowane dla praca z tablicami. Więc nie ma żadnego powodu deletemieć specjalną sprawę gotową do ponownego przeniesienia tablicy, ponieważ to po prostu spowolniłoby niepotrzebną pracę. Z perspektywy czasu moje oczekiwania były nierealistyczne.

Oczywiście, że zrobił Zaskocz mnie. Ponieważ napisałem to, aby usprawiedliwić moją krucjatę przeciwko "zerowym śmieciem":

Ignorowanie niebezpieczeństw i problemów związanych z null, a przestrzeń zmarnowana, może to być problematyczne, jeśli macierz musi być precyzyjna.

Co jest okropnym usprawiedliwieniem dla pozbycia się nulls--null jest tylko niebezpieczny, jeśli jest używany niewłaściwie i nie ma nic wspólnego z "precyzją". Prawdziwy powód, dla którego nie powinieneś delete z tablicy jest to, że pozostawianie niepotrzebnych i niechlujnych struktur danych wokół jest niechlujne i podatne na błędy.

Poniżej znajduje się wymyślony scenariusz, który jest dość długotrwały, więc możesz przejść do sekcji, Rozwiązanie, Jeśli chcesz. Jedynym powodem, dla którego zostawiam tę sekcję, jest to, że myślę, że niektórzy ludzie prawdopodobnie myślą, że to śmieszne, i nie chcę być "tym facetem", który wysyła "zabawną" odpowiedź, a potem usuwa wszystkie "zabawne" z niej później. .

... Wiem, że to głupie.

Skomplikowany i długotrwały scenariusz PDP-11

Załóżmy na przykład, że tworzysz aplikację webową, która używa serializacji JSON do przechowywania tablicy używanej dla "kart" w łańcuchu (w tym przypadku localStorage). Powiedzmy również, że kod używa indeksów numerycznych członków tablicy do "tytułowania" ich podczas rysowania na ekranie. Dlaczego to robisz, a nie tylko przechowujesz "tytuł"? Bo... powody.

Okay, powiedzmy, że próbujesz oszczędzać pamięć na żądanie tego jeden użytkownik, który uruchamia minikomputer PDP-11 z systemu UNIX z lat 1960-tych i napisał własną, opartą na języku JavaScript, zgodną z JavaScript, przyjazną dla drukarki przeglądarkę, ponieważ X11 jest bez dyskusji.

Coraz bardziej głupi scenariusz krawędzi na bok, za pomocą delete na wspomnianej macierzy spowoduje null zanieczyszczając tablicę i prawdopodobnie powodując błędy w aplikacji w późniejszym czasie. A jeśli sprawdzisz null, to w prosty sposób pomija liczby powodujące renderowanie kart [1] [2] [4] [5] ....

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

Tak, to zdecydowanie nie jest to, czego chciałeś.

Teraz ty mógłby zachowaj drugi iterator, na przykład j, aby zwiększyć tylko wtedy, gdy odczytywane są prawidłowe wartości z tablicy. Ale to nie rozwiązałoby dokładnie problemu null problem, i nadal musisz to zadowolić Troll Użytkownik PDP-11. Niestety, jego komputer właśnie nie robi wystarczająco dużo pamięci, aby pomieścić tę ostatnią liczbę całkowitą (nie pytaj, jak sobie radzi z tablicą o zmiennej szerokości ...).

Wysyła ci więc e-mail z gniewem:

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

W tej chwili jesteś na końcu dowcipu. Ten facet narzekał nieprzerwanie na twoją aplikację i chcesz mu powiedzieć, żeby się zamknął i kupił lepszy komputer.

Rozwiązanie: Array.prototype.splice

Na szczęście tablice zrobić mieć wyspecjalizowaną metodę usuwania indeksów i ponownego przydzielania pamięci: Array.prototype.splice(). Możesz napisać coś takiego:

Array.prototype.remove = function(index){
  this.splice(index,1);
}
...
array = [1, 2, 3, 4];
array.remove(2);
// Result -> [1, 2, 4]

I właśnie tak, podobał się panu PDP-11. Brawo! (Wciąż by mu to powiedziałem, chociaż ...)

Array.prototype.splice vs Array.prototype.slice

Uważam, że ważne jest, aby wskazać różnicę między tymi dwiema podobnie nazwanymi funkcjami, ponieważ oba są bardzo użyteczne.

Array.prototype.splice (start, n)

.splice() mutuje tablicę i zwraca usunięte indeksy. Tablica jest krojona, począwszy od indeksu, start, i n elementy są rozcinane. Jeśli n jest nieokreślone, cała tablica po start jest w plasterkach (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 (start, end)

.slice() jest nieniszczący i zwraca nową tablicę zawierającą wskazane indeksy start do end. Gdyby end pozostało nieokreślone, zachowanie jest takie samo jak .splice() (end = array.length). To zachowanie jest nieco trudne, ponieważ z jakiegoś powodu end indeksy od 1 zamiast 0. Nie wiem, dlaczego to robi, ale tak właśnie jest. Także jeśli end <= start, wynikiem jest pusta tablica.

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]

Tak naprawdę nie jest to, co się dzieje, ale łatwiej jest myśleć w ten sposób. Według MDN, oto co się dzieje:

// 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

Indeks określony przez end jest po prostu wykluczone z plasterka. Indeksy w nawiasach wskazują, co się kroi. Tak czy inaczej, zachowanie nie jest intuicyjne i może powodować znaczny udział błędów typu "jeden po drugim", więc może okazać się użyteczne utworzenie funkcji otoki, aby dokładniej emulować zachowanie .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);
}

Zwróć uwagę, że funkcja wrapper została zaprojektowana tak, aby była bardzo restrykcyjna pod względem typów i wróci null jeśli coś jest wyłączone. To obejmuje wstawianie ciągów takich jak "3". Pozostawia się programiście należytą dbałość o jego typy. Ma to zachęcać do dobrej praktyki programowania.

Aktualizacja dotycząca is_array()

Dotyczy to tego (obecnie usuniętego) fragmentu kodu:

function is_array(array){
    return array !== null
        && typeof array === "object"
        && typeof array.length !== "undefined"
        && array.__proto__ === Array.prototype;
}

Jak się okazuje, w rzeczywistości jest to wbudowany sposób na stwierdzenie, czy tablica jest rzeczywiście tablicą, i to jest Array.isArray(), wprowadzone w ECMAScript 5 (grudzień 2009). Znalazłem to, próbując sprawdzić, czy nie było pytania, które by zadawało, mówiąc o tablicach z obiektów, aby sprawdzić, czy istnieje lepsze rozwiązanie niż moje, czy też dodać moje, jeśli nie było żadnego. Tak więc, jeśli używasz wersji JavaScript, która jest wcześniejsza niż ECMA 5, masz polyfill. Jednak zdecydowanie zalecam, aby nie używać mojego is_array() funkcja, która nadal obsługuje stare wersje JavaScript, oznacza ciągłe wspieranie starych przeglądarek, które je wdrażają, co oznacza zachęcanie do korzystania z niezabezpieczonego oprogramowania i narażanie użytkowników na złośliwe oprogramowanie. Więc proszę, użyj Array.isArray(). Posługiwać się let i const. Skorzystaj z nowych funkcji dodawanych do tego języka. Nie rób tego użyj prefiksów dostawcy. Kasować że IE polyfill crap z twojej strony. Usuń ten XHTML <!CDATA[[... bzdury też - w 2014 r. przenieśliśmy się do HTML5. Im wcześniej wszyscy wycofają wsparcie dla tych starych / ezoterycznych przeglądarek, tym szybciej producenci przeglądarek będą postępować zgodnie ze standardami sieci i objąć nową technologię, i im szybciej będziemy mogli przejść do bezpieczniejsza sieć.


134
2017-09-18 00:56



To delete słowo kluczowe jest jednak znacznie wygodniejsze, lol - Braden Best
Podejście to nie modyfikuje oryginalnego obiektu, który może być nadal przywoływany w innym miejscu. Może to być problem, ale nie musi, w zależności od sposobu użycia, ale należy o tym pamiętać. - Tamas Czinege
@ B1KMusic Oto sposób na usunięcie elementu z tablicy: splatać - wulftone
@wulftone nope, który dzieli tablicę i nie robi nic, aby usunąć wartość. Naprawdę myślę, że najlepszym sposobem na usunięcie z tablicy, w której wymagane są określone wartości do usunięcia, jest użycie delete i wykonaj funkcję usuwania śmieci, aby to wyczyścić. - Braden Best
Nie widzę splice w twojej edycji, ale remove powinno być Array.prototype.remove = function(index) { this.splice(index, 1); }; - Ry-♦


Stare pytanie, nowoczesna odpowiedź. Korzystanie z destrukturyzacji obiektu, ECMAScript 6 funkcja, jest tak proste, jak:

const { a, ...rest } = { a: 1, b: 2, c: 3 };

Lub z próbką pytań:

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

Możesz go zobaczyć w akcji w edytorze próbnym Babel.


Edytować:

Aby ponownie przypisać do tej samej zmiennej, użyj a let:

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

92
2017-11-08 18:02



Może dlatego, że celem jest usunięcie nieruchomości z obiektu, a nie stworzenie nowej bez własności ... chociaż twoje rozwiązanie jest moim ulubionym, ponieważ wolę niezmienny sposób. - Vingt_centimes
Na pytanie "skończyć z Nowy myObject ". - Koen.
Według kangax.github.io/compat-table/esnextWłaściwości reszty obiektu nie są sfinalizowane dla ES6, mają zero implementacji przeglądarki i tylko Babel zapewnia wsparcie. - Justin C
Jest to właściwie słodka jednolinijka do przydzielania nowych obiektów bez niechcianych rekwizytów i już obsługiwana przez Node.js 8. * / 9. * z --harmony: node.green/... - Damaged Organic
To powinna być akceptowana odpowiedź w 2018 roku :) - Yulian


Inną alternatywą jest użycie Underscore.js biblioteka.

Zauważ, że _.pick() i _.omit() zarówno zwracają kopię obiektu, jak i nie modyfikują bezpośrednio oryginalnego obiektu. Przypisanie wyniku do oryginalnego obiektu powinno załatwić sprawę (nie pokazano).

Odniesienie: połączyć  _.pick (obiekt, * klawisze)

Zwróć kopię obiektu, przefiltrowaną tak, aby zawierała tylko wartości dla whitelisted keys (lub tablica ważnych kluczy).

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

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

Odniesienie: połączyć  _.omit (obiekt, * klawisze)

Zwróć kopię obiektu, przefiltrowaną w celu pominięcia klucze na czarnej liście (lub tablicę kluczy).

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

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

W przypadku tablic, _.filter() i _.reject() może być używany w podobny sposób.


67
2018-05-24 18:53



Należy pamiętać, że jeśli klucze obiektu są liczbami, może być konieczne _.omit(collection, key.toString()) - Jordan Arseno
Dlaczego link do Wikipedii, a nie do underscorejs.org? - E730
@ E730 Dobre pytanie. Nie wiem, dlaczego jeden z redaktorów zmienił go na wikipedia.org/wiki/Underscore.js. Zmieniłem go z powrotem na underscorejs.org. - Thaddeus Albers
Hmmmmm .... Podkreślenie jest ~ 100x wolniejsze niż delete obj[prop] który jest ~ 100x wolniejszy niż obj[prop] = undefined. - Jack Giffin


Termin użyty w tytule pytania Remove a property from a JavaScript object, można interpretować na kilka różnych sposobów. Jedną z nich jest usunięcie go dla całej pamięci, a lista kluczy obiektów lub druga służy tylko do usunięcia go z obiektu. Jak wspomniano w kilku innych odpowiedziach, delete słowo kluczowe jest główną częścią. Powiedzmy, że masz swój obiekt taki jak:

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

Jeśli zrobisz:

console.log(Object.keys(myJSONObject));

wynikiem będzie:

["ircEvent", "method", "regex"]

Możesz usunąć ten konkretny klucz z kluczy obiektów, takich jak:

delete myJSONObject["regex"];

Następnie użyj klucza obiektów za pomocą Object.keys(myJSONObject) byłoby:

["ircEvent", "method"]

Ale chodzi o to, że jeśli zależy ci na pamięci i chcesz, aby obiekt został usunięty z pamięci, zaleca się ustawienie go na wartość null przed usunięciem klucza:

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

Innym ważnym punktem tutaj jest ostrożność w odniesieniu do innych odniesień do tego samego obiektu. Na przykład, jeśli utworzysz zmienną taką jak:

var regex = myJSONObject["regex"];

Lub dodaj go jako nowy wskaźnik do innego obiektu, takiego jak:

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

Nawet jeśli usuniesz go z obiektu myJSONObject, ten konkretny obiekt nie zostanie usunięty z pamięci, ponieważ regex zmienna i myOtherObject["regex"] nadal mają swoje wartości. Jak więc na pewno usunąć obiekt z pamięci?

Odpowiedź brzmi: usuń wszystkie odniesienia, które posiadasz w swoim kodzie, wskazałeś na ten właśnie obiekt i również nie używać var instrukcje, aby utworzyć nowe odniesienia do tego obiektu. Ten ostatni punkt dotyczący var oświadczenia, jest jednym z najważniejszych problemów, z którymi zwykle mamy do czynienia, ponieważ używanie var instrukcje uniemożliwiłyby usunięcie utworzonego obiektu.

Co oznacza, że ​​w tym przypadku nie można usunąć tego obiektu, ponieważ utworzyłeś regex zmienna za pośrednictwem var oświadczenie, a jeśli to zrobisz:

delete regex; //False

Rezultat byłby false, co oznacza, że ​​instrukcja delete nie została wykonana zgodnie z oczekiwaniami. Ale jeśli wcześniej nie stworzyłeś tej zmiennej i tylko ją masz myOtherObject["regex"] jako ostatnie istniejące odniesienie, można to zrobić po prostu usuwając go jak:

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

Innymi słowy, obiekt JavaScript zostaje zabity, gdy tylko w kodzie nie ma odniesienia do tego obiektu.


Aktualizacja: Dzięki @AgentME:

Ustawienie właściwości na wartość null przed usunięciem nie jest możliwe   cokolwiek (chyba, że ​​obiekt został zapieczętowany przez Object.seal i   delete nie działa. Zwykle tak nie jest, chyba że konkretnie   próbować).

Aby uzyskać więcej informacji na temat Object.seal: Object.seal ()


34
2018-02-12 06:29



Mylisz się - tylko obiekty są przekazywane przez odniesienie w JavaScript, więc jeśli myJSONObject.regexWartość jest łańcuchem i przypisujesz go do innego obiektu, drugi obiekt ma kopię tej wartości. - Michał Perłakowski
Masz rację i jest to cytat: "uważaj na swoje inne odniesienia do tego samego obiektu". - Mehran Hatami


Załóżmy, że masz obiekt, który wygląda następująco:

var Hogwarts = {
    staff : [
        'Argus Filch',
        'Filius Flitwick',
        'Gilderoy Lockhart',
        'Minerva McGonagall',
        'Poppy Pomfrey',
        ...
    ],
    students : [
        'Hannah Abbott',
        'Katie Bell',
        'Susan Bones',
        'Terry Boot',
        'Lavender Brown',
        ...
    ]
};

Usuwanie właściwości obiektu

Jeśli chcesz korzystać z całości staff array, właściwym sposobem na zrobienie tego, byłoby zrobienie tego:

delete Hogwarts.staff;

Ewentualnie możesz to zrobić:

delete Hogwarts['staff'];

Podobnie, usunięcie całej tablicy uczniów zostanie wykonane przez wywołanie delete Hogwarts.students; lub delete Hogwarts['students'];.

Usuwanie indeksu tablicy

Teraz, jeśli chcesz usunąć jednego członka personelu lub ucznia, procedura jest nieco inna, ponieważ obie właściwości są same tablice.

Jeśli znasz indeks swojego pracownika, możesz to po prostu zrobić:

Hogwarts.staff.splice(3, 1);

Jeśli nie znasz indeksu, musisz również wykonać wyszukiwanie indeksu:

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

Uwaga

Choć technicznie można z niego korzystać delete w przypadku tablicy użycie jej spowodowałoby niepoprawne wyniki podczas wywoływania na przykład Hogwarts.staff.length później. Innymi słowy, delete usunie element, ale nie zaktualizuje wartości length własność. Za pomocą delete również zepsułoby indeksowanie.

Dlatego podczas usuwania wartości z obiektu zawsze najpierw rozważ, czy masz do czynienia z właściwościami obiektu, czy masz do czynienia z wartościami macierzy, i wybierz odpowiednią strategię na podstawie tego.

Jeśli chcesz poeksperymentować z tym, możesz użyć ten Fiddle jako punkt wyjścia.


30
2018-02-21 18:09



Myślę, że powinieneś zawsze używać splice na tablicę zamiast delete. - Joel Trauger
@JoelTrauger: To właśnie mówię ;-) - John Slegers
Tak. Mój komentarz jest taki delete nawet nie powinno być czymś. Jego splice jest tym, czego szukał OP. - Joel Trauger
@JoelTrauger: Jak próbowałem wyjaśnić, delete należy użyć dla właściwości obiektu i splice dla elementów tablicy. - John Slegers
Splice jest bardzo powolne. Chociaż powinno być używane zamiast delete na tablicach najlepiej byłoby nie tworzyć kodu skupionego wokół niego. - Jack Giffin


ECMAScript 2015 (lub ES6) ma wbudowane Odzwierciedlić obiekt. Możliwe jest usunięcie właściwości obiektu przez wywołanie Reflect.deleteProperty () funkcja z obiektem docelowym i kluczem właściwości jako parametrami:

Reflect.deleteProperty(myJSONObject, 'regex');

co jest równoznaczne z:

delete myJSONObject['regex'];

Ale jeśli właściwości obiektu nie można konfigurować, nie można go usunąć ani za pomocą funkcji deleteProperty ani operatora delete:

let obj = Object.freeze({ prop: "value" });
let success = Reflect.deleteProperty(obj, "prop");
console.log(success); // false
console.log(obj.prop); // value

Object.freeze () sprawia, że ​​wszystkie właściwości obiektu nie są konfigurowalne (poza innymi rzeczami). deleteProperty funkcja (jak również usuń operatora) zwraca false przy próbie usunięcia dowolnej z jego właściwości. Jeśli właściwość jest konfigurowalna, zwraca true, nawet jeśli właściwość nie istnieje.

Różnica pomiędzy delete i deleteProperty jest w trybie ścisłym:

"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

29
2018-01-10 16:36



@Gothdo ma więcej korzyści, szczególnie gdy potrzebujesz zrobić coś funkcjonalnego. Na przykład. możesz przypisać funkcję do zmiennej, przekazać jako argument lub użyć apply, call, bind Funkcje... - madox2