Питання Як очистити масив у JavaScript?


Чи є спосіб видалити масив і, якщо можливо, з ним .remove()?

Наприклад,

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

Як я можу позбутися цього?


2199
2017-08-05 09:08


походження


ось тест з різними можливостями: jsben.ch/#/7QyI1 - EscapeNetscape


Відповіді:


Способи очищення існуючого масиву A:

Спосіб 1

(це була моя оригінальна відповідь на питання)

A = [];

Цей код буде встановлювати змінну A до нового порожнього масиву. Це ідеально, якщо у вас немає посилання на вихідний масив A де-небудь ще, оскільки це насправді створює абсолютно новий (порожній) масив. Ви повинні бути обережними за допомогою цього методу, оскільки якщо ви послали цей масив з іншої змінної або властивості, вихідний масив залишиться незмінним. Використовуйте це лише тоді, коли ви посилаєтесь лише на масив за допомогою його початкової змінної A.

Це також найшвидше рішення.

Цей приклад коду показує проблему, яку ви можете зіткнутися при використанні цього методу:

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

Метод 2 (як запропонував по Метью Крамлі)

A.length = 0

Це дозволить очистити існуючий масив, встановивши його довжину до 0. Деякі стверджують, що це може не працювати у всіх реалізаціях JavaScript, але, виявляється, це не так. Він також працює при використанні "строгого режиму" в ECMAScript 5, оскільки властивість довжини масиву - це властивість читання / запису.

Метод 3 (як запропонував по Антоній)

A.splice(0,A.length)

Використовуючи .splice() буде працювати чудово, але з часів .splice() Функція повертає масив з усіма видаленими елементами, він фактично поверне копію вихідного масиву. Тести показують, що це не впливає на продуктивність.

Метод 4 (як запропонував по tanguy_k)

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

Цей варіант не дуже стислий, і це також найповільніший спосіб вирішення, на відміну від попередніх тестів, на які посилається початкова відповідь.

Продуктивність

З усіх методів очищення існуючий масив, методи 2 і 3 дуже схожі на продуктивність і набагато швидше, ніж метод 4. Див орієнтир.

Як зазначалося Діадистіс в їх відповісти нижче, оригінальні контрольні показники, які використовувались для визначення ефективності описаних вище чотирьох методів, були недоліками. Оригінальний тест повторно використовував очищений масив, тому друга ітерація очищала масив, який вже був порожнім.

Наведений нижче тест виправляє цей недолік: http://jsben.ch/#/hyj65. Це ясно показує, що методи # 2 (властивість довжини) та # 3 (сплайс) є найшвидшими (метод не враховує # 1, який не змінює оригінальний масив).


Це була гаряча тема та причина багато суперечок. Насправді є багато правильних відповідей, і тому, що дана відповідь була відмічена як прийнята відповідь дуже довго, я включу тут всі методи. Якщо ви голосуватимете за цю відповідь, будь ласка, звертайте увагу на інші відповіді, на які я посилався.


3457
2017-08-05 09:10



while (A.length) { A.pop(); }, не потрібно > 0 - Ivan Black
> 0 є більш читабельним IMHO. І немає різниці в продуктивності між цими двома. - Philippe Leybaert
@ даган, це не зовсім зрозуміло, що ви намагаєтеся сказати. b зберігає посилання на старий масив навіть після a призначається новий. c і d продовжуйте посилання на один і той же масив. Отже, очікується різниця у результатах. - shovavnik
@DiegoJancic Method # 1 не враховується, оскільки він не очищає масив. Це створює новий. Його не слід включати в тестовий показник. - Philippe Leybaert
Ви не можете використовувати while(A.pop()) у випадку, якщо елемент у масиві є помилковим. Візьмемо, наприклад, A = [2, 1, 0, -1, -2], призведе до рівняння [2, 1]. Навіть while(A.pop() !== undefined) не працює, тому що ви можете мати масив з невизначеним як один з значень. Напевно, чому компілятор не оптимізував його. - Jonathan Gawrych


Якщо вам потрібно зберегти оригінальний масив, оскільки у вас є інші посилання на нього, який також слід оновити, ви можете очистити його без створення нового масиву, встановивши його довжину до нуля:

A.length = 0;

2253
2017-08-05 16:29



@Acorn Так, він працюватиме у всіх браузерах. - Matthew Crumley
Що таке ECMAScript 5 Standard? - Pacerier
@ Пазерер: він все ще працює в ES5. З розділу 15.4: "... коли змінюється властивість довжини, кожне властивість, ім'я якого є індексом масиву, значення якого не менше, ніж нова довжина, автоматично видаляється" - Matthew Crumley
@LosManos Навіть у строгому режимі length це особлива властивість, але не тільки для читання, тому вона все одно буде працювати. - Matthew Crumley
@MattewCrumley Я зробив кілька тестів, і, схоже, a.length = 0 - це не ефективне очищення всього масиву. jsperf.com/length-equal-0-or-new-array Я думаю, якщо у вас є одна рефлексія (і ви не додали додаткових властивостей, які ви хочете зберегти), краще створити новий масив і залишити старий колектору сміття, який запускатиметься, коли це буде доречно. - Paul Brewczynski


Тут найшвидша робоча реалізація поки зберігаючи той же масив ("змінюється"):

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

FYI Карта визначає clear() тому здавалося б логічним clear() за Масив теж

Або як Underscore.js mixin:

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

Або простою функцією:

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

TypeScript версія:

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

FYI це не можна спростити while (array.pop()): тести не зможуть.

І тести, які йдуть з ним:

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

Тут оновлений jsPerf: http://jsperf.com/array-destroy/32  http://jsperf.com/array-destroy/152


256
2018-06-25 20:32



TT ваша відповідь є єдиною, яка правильна і швидка (в той же час), але має набагато менше "upvotes". Ну, здається, люди люблять гарні рішення, які є повільними: / - Ai_boy
@Naomik Але це одна з основних функцій, яка повинна була бути там за замовчуванням. - thefourtheye
@thefourtheye Хороше рішення для роботи, хоча я згоден з @naomik, ви не повинні змінювати рідні об'єкти. Говорячи про те, що воно має бути поруч з точкою, проблема полягає в тому, що ви модифікуєте глобали, що погано. Якщо ви надасте свій код іншим користувачам, то він не повинен мати непередбачених побічних ефектів. Уявіть собі, чи є інша бібліотека також змінено Array.prototype і він робив щось дещо інше, потім все на всьому коді [].clear() був трохи помилковим. Це не буде весело налагоджувати. Отже, загальним повідомленням є: Не змінюйте globals. - jpillora
@thefourtheye Весь сенс не змінювати глобальний обсяг, тому що ти не знаєш якщо хтось інший код вже (або буде), використовуючи ім'я. Я пропоную функцію всередині локальної області. Отже, всередині програми / бібліотеки IIFE, роби function clear(arr) { while(arr.length) arr.pop(); }, а потім очистити масиви з clear(arr) замість arr.clear(). - jpillora
Виявляється, цей метод є набагато повільніше, ніж .splice() і .length=0. Тести не були правильними. Подивись мою оновлену відповідь. - Philippe Leybaert


Більш зручне та оптимальне рішення, яке буде взаємно браузером, - це використання splice спосіб видалити вміст масиву A, як показано нижче:

A.splice(0, A.length);


182
2017-11-15 09:49



Чому це більш дружній для браузера? Які браузери мають проблеми з A.length? - stricjux
@ jm2 те, що ви кажете, не зовсім правда. Вона фактично змінює масив, про який йде мова, і згодом всі посилання потрапляють на неї. Див тест на моєму jsFiddle: jsfiddle.net/shamasis/dG4PH - Shamasis Bhattacharya
@alex ні, це не так splice змінює масив і повертає видалені записи. Спершу прочитайте документи: developer.mozilla.org/en-US/docs/JavaScript/Reference/... - David
Ми можемо запобігти поверненню отриманого масиву за допомогою оператор кома: A.splice(0, A.length),0;. Це призведе до повернення значення 0 так як A.length = 0; б. Отриманий масив все ще створюється і повинен змусити сценарій працювати повільніше: (jsperf ~ 56% повільніше). Впровадження браузера вплине на це, хоча я не бачу ніяких причин splice буде швидше, ніж налаштування length. - Evan Kennedy
Я теж знайшов це просто A.splice(0) також працює. - corwin.amber


Відповіді, які не менш 2739 upvotes до цих пір, є помилковими та неправильними.

Питання полягає в наступному: "Як ви видалите існуючий масив?" Наприклад, за A = [1,2,3,4].

  1. Кажучи "A = [] це відповідь "невіглася і абсолютно невірна. [] == [] є помилковий.

    Це тому, що ці два масиви - це два окремі, окремі об'єкти, які мають свою власну ідентичність, зайнявши власне місце в цифровому світі, кожен сам по собі.


Скажімо, ваша мати просить вас очистити смітник.

  • Ви не вводите новий, як якщо б ви зробили те, про що вас попросили.
  • Замість цього ви очистите смітник.
  • Ви не замінюєте заповнену нову порожню банку, і ви не візьмете мітку "А" із заповненої кані і не прикріпіть її до нового, як у A = [1,2,3,4]; A = [];

Очищення об'єкта масиву є найпростішим:

A.length = 0;

Таким чином, канал під "А" не тільки порожній, але і такий чистий, як новий!


  1. Крім того, вам не потрібно видаляти кошик вручну, поки канал не буде порожнім! Ви попросили очистити існуюче, повністю, в свою чергу, щоб не вибирати кошик, доки воно не стане порожнім, як у:

    while(A.length > 0) {
        A.pop();
    }
    
  2. Також не кладіть вашу ліву руку в нижній частині сміття, тримаючи його праворуч у верхній частині, щоб витягнути його вміст, як в:

    A.splice(0, A.length);
    

Ні, вас попросили його очистити:

A.length = 0;

Це єдиний код, який правильно звільняє вміст заданого масиву JavaScript.


61
2018-04-30 15:18



Єдина проблема із запропонованим рішенням полягає в тому, що кошик все ще існує, адже саме ви змінили дошку повідомлень, що не містить сміття. Потрібно мати посилання на старий масив. Ви можете бути впевнені, що збирач сміття при встановленні .length = 0 також видаляє всі посилання на масив і його властивості? Я думаю це робить хоч, але для мене це магія. Метод clearclean бажаний, щоб уникнути плутанини, щоб сказати щонайменше. - momo
Я ніколи не заявив, що це рішення є неправильним. Проблема полягає в тому, що вся ця нитка є абсолютно необов'язковою. Понад 3000 голосів показує, що намагаючись з'ясувати, що найкращим чином слід зробити це, достатньо випадок для розробників EMCA crack crack, щоб додати такий метод. Ніхто не повинен переходити через виявлення. Є три - чотири способи зробити це. У деяких критеріях рішення довжини значно повільні, ніж інші. Крім того, ідея встановлення .length = 0 для будь-якого розумного розробника не була б задовільною. - momo
Оскільки для виконання того, що треба, всі посилання мають бути вилучені. .length = 0 навіть не викликає метод, тому, якщо є інші дії, які виконуються, коли він встановлений на 0 (який є в більшості браузерів через визначення setter), я все ще вважаю це занадто магічним, щоб фактично довіряти, що він робить те, що він думав зробити. - momo
Тому я краще зрозуміти це сам. Чіткий метод може бути прототип, але це просто потворне. Я маю на увазі те, що ця реалізація повинна бути присутньою, щоб більше 10 000 розробників не довелося витрачати години на читання лише цієї теми, не враховуючи всіх інших, які витрачали більше часу на тестування. - momo
існує лише один спосіб очистити масив, заповнити його новими вхідними даними та знову його відкинути. Всі інші або не є, або смішно неефективні, і непробачно головий CPU. Єдиною практичною альтернативою є A(n) = A.splice( 0, A.length ); у випадку, якщо вам потрібно зробити резервну копію попереднього вмісту. р.с. Array.length є властивістю read-write \ method, якщо ви пропустили цей основний факт. Це означає, що ви можете розширити його до нової довжини, ви не можете обрізати його до того, що довжина ви хочете, і серед інших, ви можете відкинути всіх членів, скоротивши його довжину до 0. Це швейцарський нож масиву. - Bekim Bacaj


Тест продуктивності:

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



Додавання відсоткових змін незрозуміло використовувати, навіть не відзначаючи вашу платформу. На моєму комп'ютері популярність в Chrome 34 дуже повільно швидше, але насправді повільніше, ніж [] в останньому Firefox. - Matt Styles
Тестування в 32-розрядному Firefox 39.0 на 64-розрядному Windows NT 6.3, швидше за все, a = []! - Reza-S4
У цьому тесті в Chrome є безперечно щось незрозуміле. Як в пеклі може з'явитися спливаюча петля набагато швидше, ніж інші 3 рішення? - chqrlie
@chqrlie Це не так. Це найменший спосіб. Тестовий контроль є недоліком. - Philippe Leybaert
Будь ласка, видаліть цю відповідь так, як це неправильно, і посилання на безглуздий недосконалий тест як фальшиві докази. - James Wakefield


Ви можете додати це до свого JavaScript-файлу, щоб ваші масиви були "очищені":

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

Тоді ви можете використовувати його таким чином:

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

Або якщо ви хочете бути впевненими, що нічого не знищити:

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

Багато людей думають, що не слід змінювати власні об'єкти (наприклад, масив), і я схильний погодитися. Будь ласка, використовуйте обережність, щоб вирішити, як це зробити.


32
2017-12-11 02:58



@Naomik Чи можете ви пояснити свої міркування, чому робити таку річ хронювати? - Undefined
Він "нахмурився", щоб змінити примітивні функції javascript, такі як Array та String. Можливо, ви перевантажите вже існуючу функцію та скиньте клас об'єкта. Там може бути неясний движок JavaScript, який вже має чітке (), і очікує, що він поводитьсь по-іншому. Протектор уважно - це все, що я кажу. - Design by Adrian
Як про проблему, коли робити foreach над членами масиву, раптом починатимуть включення a clear ключ? - ErikE
Як довідник: Чому розширює місцеві предмети поганою практикою? - Emile Bergeron


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

І називайте це: array.clear();


16
2018-02-22 21:28



Будь ласка, не рекомендуйте модифікацію рідних об'єктів. - user633183
чому люди мають цю тенденцію захопити прийняту відповідь і поставити її в прототип функції? Ви справді робите це у своїх проектах? У вас є величезна бібліотека додаткових доповнень, які ви включаєте до кожного проекту? - nurettin
Чому б не тільки набрати array.length = 0? - Design by Adrian
@ naomik "Будь ласка, не рекомендуйте модифікацію рідних об'єктів". - Я цілковито погоджуюсь з цим, але просто повторюючи пропозицію сам по собі сприймається як нахабний. Хтось, хто пропонує такий варіант, напевно, не знає про наслідки, і викидає цю лінію на них, замість того, щоб надати коротке пояснення, або посилання не передає іншого змісту, крім "Ми, люди розумніші, ніж ти, кажуть вам не робити цього, тому що ми знаємо краще". - John Weisz
Як довідник: Чому розширює місцеві предмети поганою практикою? - Emile Bergeron


Існує чимало плутанини та дезінформації щодо часу, поп-/ зміщення продуктивності як у відповідях, так і в коментарях. Режим показу / поп має (як очікувалося) найгірша продуктивність. Що насправді відбувається, це те, що налаштування виконується лише один раз для кожного зразка, який виконує фрагмент у циклі. наприклад:

var arr = [];

for (var i = 0; i < 100; i++) { 
    arr.push(Math.random()); 
}

for (var j = 0; j < 1000; j++) {
    while (arr.length > 0) {
        arr.pop(); // this executes 100 times, not 100000
    }
}

Я створив новий тест, який працює правильно:

http://jsperf.com/empty-javascript-array-redux

УВАГА: навіть у цій версії тесту реально неможливо побачити реальну різницю, тому що клонування масиву займає більшу частину часу тесту. Це все ще показує це splice це найшвидший спосіб очистити масив (не приймаючи) [] враховуючи, що, хоча це найшвидше, фактично не очищує існуючий масив).


15
2018-02-16 18:52



Дуже хороший момент! Я оновлю оригінальну відповідь з правильними результатами тесту. - Philippe Leybaert
Я не можу повірити, що ніхто не помітив цю помилку. З більш ніж півмільйона переглядів ви очікуєте, що хтось це помітить. Велика робота Diadistis - Philippe Leybaert


Якщо ви зацікавлені в розподілі пам'яті, ви можете порівняти кожен підхід, використовуючи щось подібне це jsfiddle у поєднанні з вкладкою часової шкали інструментів chrome dev. Ви бажаєте використовувати значок смітника внизу, щоб змусити смітник збирати після "очищення" масиву. Це має дати вам більш конкретну відповідь для браузера за вашим вибором. Багато відповідей тут старі, і я не буду покладатися на них, а скоріше тестувати, як у відповідь @ tanguy_k вище.

(для введення на вищезгадану вкладку ви можете перевірити тут)

Stackoverflow змушує мене скопіювати jsfiddle так ось це:

<html>
<script>
var size = 1000*100
window.onload = function() {
  document.getElementById("quantifier").value = size
}

function scaffold()
{
  console.log("processing Scaffold...");
  a = new Array
}
function start()
{
  size = document.getElementById("quantifier").value
  console.log("Starting... quantifier is " + size);
  console.log("starting test")
  for (i=0; i<size; i++){
    a[i]="something"
  }
  console.log("done...")
}

function tearDown()
{
  console.log("processing teardown");
  a.length=0
}

</script>
<body>
    <span style="color:green;">Quantifier:</span>
    <input id="quantifier" style="color:green;" type="text"></input>
    <button onclick="scaffold()">Scaffold</button>
    <button onclick="start()">Start</button>
    <button onclick="tearDown()">Clean</button>
    <br/>
</body>
</html>

І ви повинні звернути увагу, що це може залежати від типу елементів масиву, оскільки JavaScript керує рядками інакше, ніж інші примітивні типи, не кажучи вже про масиви об'єктів. Тип може вплинути на те, що відбувається.


14
2017-12-11 23:19





A.splice(0);

Я просто зробив це на деякому коді, над яким я працюю. Це очистило масив.


10
2018-01-29 19:24



Ні, ви просто помістили іменований масив-контейнер з новоствореним анонімним. `var A = [1,2,3,4]; var B; B = A.splice (0); console.log (A); console.log (B); ' - Bekim Bacaj