Pytanie Jak opróżnić tablicę w JavaScript?


Czy istnieje sposób na opróżnienie tablicy, a jeśli tak, to możliwe .remove()?

Na przykład,

A = [1,2,3,4];

Jak mogę to opróżnić?


2199
2017-08-05 09:08


pochodzenie


tutaj benchmark z różnymi możliwościami: jsben.ch/#/7QyI1 - EscapeNetscape


Odpowiedzi:


Sposoby usuwania istniejącej macierzy A:

Metoda 1

(to była moja oryginalna odpowiedź na pytanie)

A = [];

Ten kod ustawi zmienną A do nowej pustej tablicy. To jest idealne, jeśli nie masz odniesienia do oryginalnej tablicy A nigdzie indziej, ponieważ to faktycznie tworzy zupełnie nową (pustą) tablicę. Powinieneś uważać na tę metodę, ponieważ jeśli odwołasz się do tej tablicy z innej zmiennej lub właściwości, pierwotna tablica pozostanie niezmieniona. Używaj tego tylko, jeśli odwołujesz się tylko do tablicy za pomocą jej oryginalnej zmiennej A.

Jest to również najszybsze rozwiązanie.

Ten przykładowy kod pokazuje problem, który możesz napotkać podczas używania tej metody:

var arr1 = ['a','b','c','d','e','f'];
var arr2 = arr1;  // Reference arr1 by another variable 
arr1 = [];
console.log(arr2); // Output ['a','b','c','d','e','f']

Metoda 2 (tak jak zasugerował przez Matthew Crumley)

A.length = 0

Spowoduje to wyczyszczenie istniejącej macierzy, ustawiając jej długość na 0. Niektórzy twierdzą, że to może nie działać we wszystkich implementacjach JavaScript, ale okazuje się, że tak nie jest. Działa również przy użyciu "trybu ścisłego" w ECMAScript 5, ponieważ właściwość length tablicy jest właściwością odczytu / zapisu.

Metoda 3 (tak jak zasugerował przez Anthony)

A.splice(0,A.length)

Za pomocą .splice() będzie działać idealnie, ale od .splice() funkcja zwróci tablicę ze wszystkimi usuniętymi elementami, to faktycznie zwróci kopię oryginalnej tablicy. Testy porównawcze sugerują, że nie ma to żadnego wpływu na wydajność.

Metoda 4 (tak jak zasugerował przez tanguy_k)

while(A.length > 0) {
    A.pop();
}

To rozwiązanie nie jest zbyt zwięzłe i jest także najwolniejszym rozwiązaniem, w przeciwieństwie do wcześniejszych testów porównawczych, o których mowa w pierwotnej odpowiedzi.

Wydajność

Ze wszystkich metod oczyszczania istniejąca tablica, metody 2 i 3 są bardzo podobne pod względem wydajności i są dużo szybsze niż metoda 4. Zobacz to reper.

Jak wskazano przez Diadistis w ich odpowiedź poniżej oryginalne testy porównawcze, które zostały wykorzystane do określenia wydajności czterech opisanych powyżej metod, były wadliwe. Pierwotny wzorzec ponownie wykorzystał wyczyszczoną tablicę, więc druga iteracja wyczyściła tablicę, która była już pusta.

Poniższy test porównawczy rozwiązuje tę lukę: http://jsben.ch/#/hyj65. Wyraźnie widać, że metody # 2 (właściwość długości) i # 3 (splice) są najszybszymi (nie licząc metody # 1, która nie zmienia oryginalnej tablicy).


To był gorący temat i przyczyna wielu kontrowersji. W rzeczywistości jest wiele poprawnych odpowiedzi, a ponieważ ta odpowiedź została przez długi czas oznaczona jako zaakceptowana odpowiedź, uwzględnię tutaj wszystkie metody. Jeśli zagłosujesz na tę odpowiedź, przekaż pozostałe odpowiedzi, które również zostały przeze mnie wymienione.


3457
2017-08-05 09:10



while (A.length) { A.pop(); }, nie ma potrzeby > 0 - Ivan Black
> 0 jest bardziej czytelny IMHO. I nie ma różnicy w wydajności między nimi. - Philippe Leybaert
@daghan, nie jest wcale jasne, co próbujesz powiedzieć. b zawiera odniesienie do starej tablicy nawet po a jest przypisany nowy. c i d kontynuuj odwoływanie się do tej samej tablicy. Dlatego oczekuje się różnicy w wynikach. - shovavnik
@DiegoJancic Metoda nr 1 nie jest liczona, ponieważ nie powoduje wyczyszczenia tablicy. Tworzy nową. Nie należy go włączać do benchmarku. - Philippe Leybaert
Nie możesz użyć while(A.pop()) w przypadku, gdy element w tablicy jest falsey. Weźmy na przykład A = [2, 1, 0, -1, -2] dałoby A równe [2, 1]. Parzysty while(A.pop() !== undefined) nie działa, ponieważ możesz mieć tablicę z undefined jako jedną z wartości. Prawdopodobnie dlatego kompilator go nie optymalizuje. - Jonathan Gawrych


Jeśli chcesz zachować oryginalną tablicę, ponieważ masz inne odniesienia do niej, które również powinny zostać zaktualizowane, możesz wyczyścić ją bez tworzenia nowej tablicy, ustawiając jej długość na zero:

A.length = 0;

2253
2017-08-05 16:29



@Acorn Tak, będzie działać we wszystkich przeglądarkach. - Matthew Crumley
co mówi o tym ECMAScript 5 Standard? - Pacerier
@Pacerier: Nadal działa w wersji ES5. Z sekcji 15.4: "... w przypadku zmiany właściwości length każda właściwość, której nazwa jest indeksem tablicy, której wartość nie jest mniejsza niż nowa długość, jest automatycznie usuwana" - Matthew Crumley
@LosManos Nawet w trybie ścisłym, length jest specjalną własnością, ale nie tylko do odczytu, więc nadal będzie działać. - Matthew Crumley
@MattewCrumley Zrobiłem test, i wygląda na to, że a.length = 0 nie jest efektywnym czyszczeniem całej tablicy. jsperf.com/length-equal-0-or-new-array Myślę, że jeśli masz jedną odpowiedź (i nie dodałeś żadnych dodatkowych właściwości, które chcesz zachować), lepiej jest utworzyć nową tablicę i pozostawić ją w garbage collectorze, która będzie działać, gdy będzie to właściwe. - Paul Brewczynski


Oto najszybsza działająca implementacja podczas zachowując tę ​​samą tablicę ("zmienny"):

Array.prototype.clear = function() {
  while (this.length) {
    this.pop();
  }
};

FYI Mapa definiuje clear() więc wydaje się to logiczne clear() dla Szyk także.

Lub jako Underscore.js mixin:

_.mixin({
  clearArray: function(array) {
    while (array.length) {
      array.pop();
    }
  }
});

Lub prosta funkcja:

function clearArray(array) {
  while (array.length) {
    array.pop();
  }
}

Maszynopis wersja:

function clearArray<T>(array: T[]) {
  while (array.length) {
    array.pop();
  }
}

Do tego nie można uprościć while (array.pop()): testy zakończą się niepowodzeniem.

I testy, które się z tym wiążą:

describe('Array', () => {
  it('should clear the array', () => {
    let array = [1, 2, 3, 4, 5];
    array.clear();
    expect(array.length).toEqual(0);
    expect(array[0]).toEqual(undefined);
    expect(array[4]).toEqual(undefined);

    // Even with undefined or null inside
    array = [1, undefined, 3, null, 5];
    array.clear();
    expect(array.length).toEqual(0);
    expect(array[0]).toEqual(undefined);
    expect(array[4]).toEqual(undefined);
  });
});

Tutaj zaktualizowany jsPerf: http://jsperf.com/array-destroy/32  http://jsperf.com/array-destroy/152


256
2018-06-25 20:32



TT twoja odpowiedź jest jedyną, która jest poprawna i szybka (w tym samym czasie), ale ma znacznie mniej "upvotes". Wygląda na to, że ludzie lubią ładne rozwiązania, które są powolne: / - Ai_boy
@naomik Ale jest to jedna z podstawowych funkcjonalności, które powinny być tam domyślnie. - thefourtheye
@thefourtheye Dobre rozwiązanie dla wydajności, chociaż zgadzam się z @naomik, nie powinieneś modyfikować natywnych obiektów. Mówienie, że powinno tam być, jest poza kwestią, problem polega na tym, że modyfikujesz globals, co jest złe. Jeśli podajesz swój kod innym użytkownikom, to nie powinno to mieć żadnych nieprzewidzianych skutków ubocznych. Wyobraź sobie, że jest inna biblioteka również zmodyfikowano Array.prototype i robił coś nieco innego, a potem cały kod [].clear() było trochę nie tak. Nie byłoby fajnie debugować. Tak więc ogólna wiadomość brzmi: Nie modyfikuj globów. - jpillora
@thefourtheye Cała kwestia niezmieniania globalnego zasięgu jest taka, ponieważ nie będziesz wiedział jeśli kod kogoś innego jest już (lub będzie) używał tej nazwy. Proponuję funkcję wewnątrz zakresu lokalnego. Tak więc, wewnątrz twojej aplikacji / biblioteki IIFE, robić function clear(arr) { while(arr.length) arr.pop(); }, następnie wyczyść tablice przy pomocy clear(arr) zamiast arr.clear(). - jpillora
Okazuje się, że ta metoda jest dużo wolniejsza niż .splice() i .length=0. Testy porównawcze nie były poprawne. Zobacz moją zaktualizowaną odpowiedź. - Philippe Leybaert


Bardziej optymalnym rozwiązaniem dla wielu przeglądarek i bardziej optymalnym rozwiązaniem będzie użycie splice metoda opróżniania zawartości tablicy A jak poniżej:

A.splice(0, A.length);


182
2017-11-15 09:49



Dlaczego jest bardziej przyjazny dla różnych przeglądarek? Jakie przeglądarki mają problemy z A.length? - stricjux
@ jm2 to, co mówisz, nie jest do końca prawdą. W rzeczywistości modyfikuje ona omawianą macierz, a następnie wpływa na wszystkie odniesienia. Zobacz test na moim jsFiddle: jsfiddle.net/shamasis/dG4PH - Shamasis Bhattacharya
@alex nie, nie, splice modyfikuje tablicę i zwraca usunięte wpisy. Przeczytaj najpierw dokumenty: developer.mozilla.org/en-US/docs/JavaScript/Reference/... - David
Możemy zapobiec zwróceniu wynikowej tablicy przy użyciu parametru operator przecinka: A.splice(0, A.length),0;. To zostawi wartość zwracaną przez 0 tak jak A.length = 0; by. Wynikowa tablica jest nadal tworzona i powinien spowolnić działanie skryptu: (jsperf ~ 56% wolniej). Implementacja przeglądarki wpłynie na to, chociaż nie widzę powodu, dlaczego splice byłaby szybsza niż ustawienie length. - Evan Kennedy
Zauważyłem też, że właśnie A.splice(0) działa również. - corwin.amber


Odpowiedzi, które nie mniej niż 2739 są teraz błędne, są mylące i błędne.

Pytanie brzmi: "Jak opróżnić istniejącą tablicę?" Na przykład. dla A = [1,2,3,4].

  1. Mówiąc "A = [] jest odpowiedzią "jest nieświadomy i absolutnie niepoprawny. [] == [] jest fałszywy.

    Dzieje się tak dlatego, że te dwie macierze są dwoma oddzielnymi, indywidualnymi obiektami, z ich własnymi dwiema tożsamościami, zajmującymi swoją własną przestrzeń w cyfrowym świecie, każdy samodzielnie.


Powiedzmy, że twoja matka prosi cię o opróżnienie kosza na śmieci.

  • Nie przynosisz nowego, jakbyś zrobił to, o co cię poprosiono.
  • Zamiast tego opróżniasz kosz.
  • Nie zamieniasz wypełnionej pustej puszki i nie bierzesz etykiety "A" z wypełnionej puszki i nie wkładasz jej do nowej, jak w A = [1,2,3,4]; A = [];

Opróżnianie obiektu tablicy jest najłatwiejszą rzeczą:

A.length = 0;

W ten sposób puszka pod "A" jest nie tylko pusta, ale także czysta jak nowa!


  1. Co więcej, nie musisz usuwać kosza ręcznie, aż do opróżnienia puszki! Zostałeś poproszony o opróżnienie już istniejącego, całkowicie, w jednej turze, aby nie podnosić śmieci aż do opróżnienia puszki, jak w:

    while(A.length > 0) {
        A.pop();
    }
    
  2. Aby umieścić lewą rękę u dołu kosza, trzymaj ją prawą u góry, aby móc wyciągnąć jej zawartość w następujący sposób:

    A.splice(0, A.length);
    

Nie, poproszono Cię o opróżnienie:

A.length = 0;

Jest to jedyny kod, który poprawnie opróżnia zawartość danej tablicy JavaScript.


61
2018-04-30 15:18



Jedynym problemem z sugerowanym rozwiązaniem jest to, że kosz nadal istnieje, po prostu zmieniłeś tablicę informacyjną, mówiąc, że nie ma żadnych śmieci. Powinno nadal istnieć odniesienie do starej tablicy. Czy możesz mieć pewność, że garbage collector ustawiając .length = 0, usunie również wszystkie odniesienia do tablicy i jej właściwości? Myślę, że tak, ale dla mnie to magia. Konieczna jest metoda .clear (), aby uniknąć pomyłki. - momo
Nigdy nie twierdziłem, że to rozwiązanie jest złe. Problem polega na tym, że cały wątek jest zupełnie niepotrzebny. Ponad 3000 głosów pokazuje, że próba znalezienia najlepszego rozwiązania powinna sprawić, że będzie to wystarczająco ważny przypadek dla deweloperów pęknięć EMCA, którzy dodadzą taką metodę. Nikt nie powinien tego robić. Istnieją trzy - cztery różne sposoby, aby to zrobić. W niektórych benchmarkach rozwiązania długości są znacznie wolniejsze niż inne. Ponadto pomysł ustawienia .length = 0 dla każdego rozsądnego dewelopera nie byłby zadowalający. - momo
Ponieważ aby osiągnąć to, co powinno, wszystkie odniesienia muszą zostać usunięte. .length = 0 nie jest nawet wywołaniem metody, więc jeśli istnieją inne działania podejmowane, gdy jest ustawione na 0 (które jest w większości przeglądarek za pomocą definiującego ustawiacza), nadal uważam, że to zbyt magiczne, aby rzeczywiście ufać, że robi to, co powinno do zrobienia. - momo
Dlatego wolę to oczyścić. Jasna metoda może być prototypowana, ale jest po prostu brzydka. Chodzi mi o to, że ta implementacja powinna już być obecna, aby ponad 10 000 programistów nie musiało spędzać godzin na lekturze właśnie tego wątku, nie biorąc pod uwagę wszystkich innych, którzy spędzali więcej czasu na testach porównawczych. - momo
jest tylko jeden sposób, aby opróżnić swoją tablicę, wypełnić ją nowymi danymi przychodzącymi i odrzucić ją ponownie. Wszystkie inne są albo nie, albo są śmiesznie nieefektywne i niewybaczalnie głodne cpu. Jedyna praktyczna alternatywa to A(n) = A.splice( 0, A.length ); na wypadek, gdybyś zrobił kopię zapasową poprzedniej zawartości. p.s. Array.length jest właściwością \ do odczytu \ zapisu w przypadku, gdy pominiesz ten podstawowy fakt. Oznacza to, że możesz rozszerzyć ją na nową długość, nie możesz jej przyciąć do dowolnej długości, a między innymi możesz odrzucić wszystkie elementy, skracając jej długość do 0. To szwajcarski nóż tablicy. - Bekim Bacaj


Test wydajności:

http://jsperf.com/array-clear-methods/3

a = []; // 37% slower
a.length = 0; // 89% slower
a.splice(0, a.length)  // 97% slower
while (a.length > 0) {
    a.pop();
} // Fastest

59
2018-05-14 07:14



Dodanie zmian procentowych nie jest zbyt użyteczne bez zauważenia twojej platformy. Na moim komputerze pop jest bardzo łagodnie szybszy w Chrome 34, ale w rzeczywistości wolniejszy niż [] w najnowszym Firefoksie. - Matt Styles
Testowanie w Firefoksie 39.0 32-bitowe w Windows NT 6.3 64-bit, a = [] jest najszybszy! - Reza-S4
W tym wyniku testu w Chrome jest zdecydowanie coś podejrzanego. Jak, do diabła, popping loop może być o wiele szybszy niż pozostałe 3 rozwiązania? - chqrlie
@chqrlie To nie jest. To najwolniejsza metoda. Test porównawczy jest wadliwy. - Philippe Leybaert
Proszę usunąć tę odpowiedź, ponieważ jest ona błędna, i łączy się z bezsensownym błędnym testem jako fałszywym dowodem. - James Wakefield


Możesz dodać to do pliku JavaScript, aby umożliwić wyczyszczenie tablic:

Array.prototype.clear = function() {
    this.splice(0, this.length);
};

Następnie możesz go użyć w następujący sposób:

var list = [1, 2, 3];
list.clear();

Lub jeśli chcesz mieć pewność, że coś nie zniszczysz:

if (!Array.prototype.clear) {
    Array.prototype.clear = function() {
       this.splice(0, this.length);
    };
}

Wiele osób uważa, że ​​nie powinieneś modyfikować obiektów natywnych (takich jak Array) i jestem skłonny się z tym zgodzić. Zachowaj ostrożność przy podejmowaniu decyzji, jak sobie z tym poradzić.


32
2017-12-11 02:58



@naomik Czy możesz wyjaśnić swoje rozumowanie, dlaczego takie rzeczy są mile widziane? - Undefined
Jest "niezadowolony", aby zmodyfikować prymitywne funkcje javascript, takie jak Array i String. Możliwe, że przeciążasz już istniejącą funkcję i wyniszczasz klasę obiektu. Może istnieć niewyraźny mechanizm javascript, który już ma clear () i oczekuje, że zachowa się inaczej. Uważnie śledzę tylko to, co mówię. - Design by Adrian
Jak o problemie, gdzie robienie foreach nad członkami tablicy nagle zaczyna się od clear klawisz? - ErikE
Jako odniesienie: Dlaczego rozszerzanie rodzimych obiektów jest złą praktyką? - Emile Bergeron