Удаление элементов массива в JavaScript - удаление против сращивания


1334

В чем разница между использованием в deleteоператор на элементе массива в отличие от использования в Array.spliceметод ?

Например:

myArray = ['a', 'b', 'c', 'd'];

delete myArray[1];
//  or
myArray.splice (1, 1);

Зачем даже метод сращивания, если я могу удалять элементы массива, как я могу с объектами?


3
Для .spliceв циклах, взгляните на этот вопрос: Удалить из массива в JavaScript .
Роб W

6
@andynormancx Да, но этот ответ был опубликован буквально на следующий день и получил гораздо больше голосов - я бы сказал, что лучше написать, так и должно быть.
Камило Мартин

@andynormancx - похоже, он не является точной копией. Вопрос, который вы связали, в основном спрашивает, почему удаление элемента из массива (что делает его разреженным) не приведет к уменьшению его длины. Этот вопрос задает различия между deleteи Array.prototype.splice.
чхарвей

@chharvey согласился, что более важно, хотя как этот вопрос был опубликован 9 лет назад! Я чувствую себя старым, чтобы вернуться сюда и комментировать это
andynormancx

Ответы:


1693

deleteудалит свойство объекта, но не будет переиндексировать массив или обновит его длину. Это заставляет это казаться, как будто это не определено:

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> delete myArray[0]
  true
> myArray[0]
  undefined

Обратите внимание , что это не на самом деле устанавливается на значение undefined, а свойство удаляется из массива, что делает его казаться неопределенным. Инструменты разработчика Chrome проясняют это различие, печатая emptyпри регистрации массива.

> myArray[0]
  undefined
> myArray
  [empty, "b", "c", "d"]

myArray.splice(start, deleteCount) фактически удаляет элемент, переиндексирует массив и изменяет его длину.

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> myArray.splice(0, 2)
  ["a", "b"]
> myArray
  ["c", "d"]

74
На самом деле, delete действительно удалить элемент, но не индексировать массив или обновить его длину (которая уже подразумеваемой бывший , так как длина всегда самый высокий показатель + 1).
Феликс Клинг

3
JSlint не любит delete myArray[0]синтаксис, говорящий « Ожидается оператор и вместо этого он видит« удалить ». » spliceРекомендуется использовать.
Глаз

21
@Eye: На самом деле JSLint просто жалуется на отсутствие точки с запятой в предыдущей строке. И вы не можете действительно рекомендовать одно над другим, так как они делают совершенно разные вещи…
Ry-

3
«Удалить в этом случае будет только установить элемент как неопределенный:« Нет, это категорически неверно. Есть принципиальная разница между delete myArray[0]и myArray[0] = undefined. В первом случае свойство полностью удаляется из объекта массива. Во втором случае свойство остается со значением undefined.
TJ Crowder

1
К сведению, инструменты Chrome dev показывают ключевое слово emptyвместо того, undefinedчтобы улучшить различие между фактически удаленным (или неинициализированным) элементом массива и элементом, который имеет реальное значение undefined. Обратите внимание, что когда я говорю это, я имею в виду, что он отображается только как emptyи не относится к реальному названному значению empty(которое не существует).
chharvey

340

Метод Array.remove ()

Джон Резиг , создатель jQuery, создал очень удобный Array.removeметод, который я всегда использую в своих проектах.

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};

и вот несколько примеров того, как это можно использовать:

// Remove the second item from the array
array.remove(1);
// Remove the second-to-last item from the array
array.remove(-2);
// Remove the second and third items from the array
array.remove(1,2);
// Remove the last and second-to-last items from the array
array.remove(-2,-1);

Сайт Джона


4
+1 Для Array.remove (). Однако не очень приятно, когда передаются строковые аргументы (в отличие от большинства методов Array, например [1,2,3].slice('1'); // =[2,3]), поэтому безопаснее изменить его наvar rest = this.slice(parseInt(to || from) + 1 || this.length);
Ричард Инглис

1
@tomwrong, в javascript нет потоков, и функция выполняется this.push.apply(this, rest), а затем возвращает возвращенное значение
billy

59
Это не отвечает на вопрос вообще.
Ry-

16
Почему бы просто не использовать splice ()? Имя этой функции, имена параметров и результаты не очевидны. Я рекомендую просто использовать сплайс (индекс, длина) - (см. Ответ Энди Хьюма)
auco

3
Функция, представленная выше, работает как объяснено, но создает нежелательные побочные эффекты при переборе массива с for(var i in array)циклом. Я удалил его и использовал вместо него сращивание.
alexykot

104

Поскольку delete удаляет только объект из элемента в массиве, длина массива не изменится. Splice удаляет объект и сокращает массив.

Следующий код будет отображать «a», «b», «undefined», «d»

myArray = ['a', 'b', 'c', 'd']; delete myArray[2];

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}

Принимая во внимание, что это будет отображать «a», «b», «d»

myArray = ['a', 'b', 'c', 'd']; myArray.splice(2,1);

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}

11
Отличный пример, за исключением неоднозначности во втором примере с использованием 1,1 - первый 1 относится к индексу в массиве, чтобы начать соединение, второй 1 - это количество элементов, которые нужно удалить. Таким образом, чтобы удалить 'c' из исходного массива, используйтеmyArray.splice(2,1)
iancoleman

68

Я наткнулся на этот вопрос, пытаясь понять, как удалить каждое вхождение элемента из массива. Вот сравнение из spliceи deleteдля удаления каждого 'c'из itemsмассива.

var items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  items.splice(items.indexOf('c'), 1);
}

console.log(items); // ["a", "b", "d", "a", "b", "d"]

items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  delete items[items.indexOf('c')];
}

console.log(items); // ["a", "b", undefined, "d", "a", "b", undefined, "d"]

14

Из Базовой Справки по JavaScript 1.5> Операторы> Специальные операторы> Оператор удаления :

Когда вы удаляете элемент массива, длина массива не изменяется. Например, если вы удалите [3], a [4] будет по-прежнему [4], а [3] не определено. Это сохраняется, даже если вы удалите последний элемент массива (delete a [a.length-1]).


10

splice будет работать с числовыми индексами.

тогда как deleteмогут быть использованы против других видов индексов ..

пример:

delete myArray['text1'];

9
Когда вы говорите «любые другие виды индексов», вы больше не говорите о массивах, а скорее об объектах, о которых спрашивает OP.
И Цзян

2
@YiJiang: массивы являются объектами. Indizes являются свойствами. Нет никакой разницы.
Берги

9

Вероятно, стоит упомянуть, что сплайс работает только с массивами. (На свойства объекта нельзя полагаться, чтобы следовать последовательному порядку.)

Чтобы удалить пару ключ-значение из объекта, фактически удалите то, что вам нужно:

delete myObj.propName;     // , or:
delete myObj["propName"];  // Equivalent.

delete не переупорядочивает ключи массива, поэтому: var arr = [1,2,3,4,5]; удалить обр [3]; for (var i = 0; i <= arr.length; i ++) console.log (arr [i]); будет демонстрировать неожиданные результаты.
Кристиан Уильямс

Это правда. Поэтому, если вы не хотите оставить неопределенный элемент в этом месте, НЕ используйте delete для ключей массива! Первоначально я добавил этот комментарий, чтобы включить ссылку на правильное использование удаления.
Jtrick

но почему delete бросит неожиданный результат ??
Алекс

9

удалить против сращивания

когда вы удаляете элемент из массива

var arr = [1,2,3,4]; delete arr[2]; //result [1, 2, 3:, 4]
console.log(arr)

когда ты склеиваешь

var arr = [1,2,3,4]; arr.splice(1,1); //result [1, 3, 4]
console.log(arr);

в случае удаления от элемента удаляется , но индекс остается пустым

в то время как в случае сращивания элемент удаляется, а индекс остальных элементов соответственно уменьшается


8

Как уже много раз говорилось выше, использование splice()кажется идеальным. Документация в Mozilla:

splice()Метод изменяет содержимое массива путем удаления существующих элементов и / или добавления новых элементов.

var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];

myFish.splice(2, 0, 'drum'); 
// myFish is ["angel", "clown", "drum", "mandarin", "sturgeon"]

myFish.splice(2, 1); 
// myFish is ["angel", "clown", "mandarin", "sturgeon"]

Синтаксис

array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)

параметры

Начните

Индекс, с которого начинается изменение массива. Если он больше длины массива, фактический начальный индекс будет установлен равным длине массива. Если отрицательный, начнется так много элементов с конца.

deleteCount

Целое число, указывающее количество удаляемых старых элементов массива. Если deleteCount равен 0, элементы не удаляются. В этом случае вы должны указать хотя бы один новый элемент. Если deleteCount больше, чем количество элементов, оставшихся в массиве, начиная с начала, то все элементы до конца массива будут удалены.

Если deleteCount не указан, deleteCount будет равен (arr.length - start).

item1, item2, ...

Элементы для добавления в массив, начиная с начального индекса. Если вы не укажете какие-либо элементы, splice()будут удалены только элементы из массива.

Возвращаемое значение

Массив, содержащий удаленные элементы. Если удаляется только один элемент, возвращается массив из одного элемента. Если никакие элементы не удалены, возвращается пустой массив.

[...]


@ downvoter: почему downvote? хочешь объяснить или нет?
серв-

7

delete действует как нереальная ситуация, он просто удаляет элемент, но длина массива остается неизменной:

пример из терминала терминала:

> var arr = ["a","b","c","d"];
> delete arr[2]
true
> arr
[ 'a', 'b', , 'd', 'e' ]

Вот функция для удаления элемента массива по индексу, используя slice () , в качестве первого аргумента она принимает arr, а в качестве второго аргумента - индекс члена, который вы хотите удалить. Как видите, он на самом деле удаляет член массива и уменьшает длину массива на 1

function(arr,arrIndex){
    return arr.slice(0,arrIndex).concat(arr.slice(arrIndex + 1));
}

Функция, приведенная выше, заключается в получении всех элементов до индекса и всех членов после индекса, объединяет их вместе и возвращает результат.

Вот пример использования функции выше в качестве модуля узла, где будет полезен терминал:

> var arr = ["a","b","c","d"]
> arr
[ 'a', 'b', 'c', 'd' ]
> arr.length
4 
> var arrayRemoveIndex = require("./lib/array_remove_index");
> var newArray = arrayRemoveIndex(arr,arr.indexOf('c'))
> newArray
[ 'a', 'b', 'd' ] // c ya later
> newArray.length
3

обратите внимание, что это не будет работать с одним массивом, содержащим дубликаты, потому что indexOf ("c") просто получит первое вхождение, и только склеит и удалит первый найденный символ "c".


6

Если вы хотите выполнить итерацию большого массива и выборочно удалять элементы, было бы дорого вызывать splice () для каждого удаления, так как splice () должен будет каждый раз переиндексировать последующие элементы. Поскольку массивы являются ассоциативными в Javascript, было бы более эффективно удалить отдельные элементы, а затем повторно индексировать массив впоследствии.

Вы можете сделать это, создав новый массив. например

function reindexArray( array )
{
       var result = [];
        for( var key in array )
                result.push( array[key] );
        return result;
};

Но я не думаю, что вы можете изменить значения ключей в исходном массиве, что было бы более эффективно - похоже, вам, возможно, придется создать новый массив.

Обратите внимание, что вам не нужно проверять «неопределенные» записи, так как они на самом деле не существуют и цикл for не возвращает их. Это артефакт печати массива, который отображает их как неопределенные. Они, кажется, не существуют в памяти.

Было бы хорошо, если бы вы могли использовать что-то вроде slice (), которое было бы быстрее, но не переиндексирует. Кто-нибудь знает лучший способ?


На самом деле, вы, вероятно, можете сделать это на месте следующим образом, что, вероятно, является более эффективным, с точки зрения производительности:

reindexArray : function( array )
{
    var index = 0;                          // The index where the element should be
    for( var key in array )                 // Iterate the array
    {
        if( parseInt( key ) !== index )     // If the element is out of sequence
        {
            array[index] = array[key];      // Move it to the correct, earlier position in the array
            ++index;                        // Update the index
        }
    }

    array.splice( index );  // Remove any remaining elements (These will be duplicates of earlier items)
},

Я считаю индекс ++; должно произойти за пределами «если». Делая правку
mishal153

6

Вы можете использовать что-то вроде этого

var my_array = [1,2,3,4,5,6];
delete my_array[4];
console.log(my_array.filter(function(a){return typeof a !== 'undefined';})); // [1,2,3,4,6]


это более интуитивно понятно, чем sliceесли бы вы пришли из функционального фона (хотя, вероятно, менее эффективно).
Джет

3

Почему не просто фильтр? Я думаю, что это самый понятный способ рассмотреть массивы в JS.

myArray = myArray.filter(function(item){
    return item.anProperty != whoShouldBeDeleted
});

Как насчет массива с сотнями (если не тысячами) записей, из которых нужно удалить только 3 из них?
Джоэл Эрнандес

хорошая точка зрения. Я использую этот метод для разреженных массивов, длина которых не превышает 200 или 300 и работает очень хорошо. Тем не менее, я думаю, что библиотеки, такие как подчеркивание, должны быть предпочтительнее, если вам нужно управлять такими большими массивами.
Аскан

1
Тем не менее, это кажется намного лучше, чем deleteили sliceдля меня.
Juneyoung Oh

3

Разницу можно увидеть, зарегистрировав длину каждого массива после применения deleteоператора и splice()метода. Например:

оператор удаления

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
delete trees[3];

console.log(trees); // ["redwood", "bay", "cedar", empty, "maple"]
console.log(trees.length); // 5

deleteОператор удаляет элемент из массива, но «заполнитель» элемента по- прежнему существует. oakбыл удален, но все еще занимает место в массиве. Из-за этого длина массива остается 5.

метод splice ()

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);

console.log(trees); // ["redwood", "bay", "cedar", "maple"]
console.log(trees.length); // 4

splice()Метод полностью удаляет целевое значение и в «заполнитель» , а также. oakбыл удален, а также пространство, которое он занимал в массиве. Длина массива теперь 4.


2
function remove_array_value(array, value) {
    var index = array.indexOf(value);
    if (index >= 0) {
        array.splice(index, 1);
        reindex_array(array);
    }
}
function reindex_array(array) {
   var result = [];
    for (var key in array) {
        result.push(array[key]);
    }
    return result;
}

пример:

var example_arr = ['apple', 'banana', 'lemon'];   // length = 3
remove_array_value(example_arr, 'banana');

банан удаляется и длина массива = 2


2

Это разные вещи, которые имеют разные цели.

spliceявляется специфичным для массива и, когда используется для удаления, удаляет записи из массива и перемещает все предыдущие записи вверх, чтобы заполнить пробел. (Он также может быть использован для вставки записей, или обоих одновременно.) spliceИзменит lengthмассив (при условии, что это не вызов no-op:) theArray.splice(x, 0).

deleteне зависит от массива; он предназначен для использования на объектах: он удаляет свойство (пара ключ / значение) из объекта, на котором вы его используете. Это применимо только к массивам, потому что стандартные (например, нетипизированные) массивы в JavaScript на самом деле вообще не являются массивами *, это объекты со специальной обработкой для определенных свойств, таких как те, чьи имена являются «индексами массива» (которые являются определяется как строковые имена "... чье числовое значение iнаходится в диапазоне +0 ≤ i < 2^32-1") и length. Когда вы используете deleteдля удаления записи массива, все, что он делает, это удаляет запись; он не перемещает другие записи, следующие за ним, чтобы заполнить пробел, и поэтому массив становится "разреженным" (некоторые записи полностью отсутствуют). Это не влияет на length.

В паре текущих ответов на этот вопрос неправильно deleteуказано, что при использовании «устанавливает запись в undefined». Это не правильно. Он полностью удаляет запись (свойство), оставляя пробел.

Давайте использовать некоторый код, чтобы проиллюстрировать различия:

console.log("Using `splice`:");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
a.splice(0, 1);
console.log(a.length);            // 4
console.log(a[0]);                // "b"

console.log("Using `delete`");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
delete a[0];
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // false
console.log(a.hasOwnProperty(0)); // false

console.log("Setting to `undefined`");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
a[0] = undefined;
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // true
console.log(a.hasOwnProperty(0)); // true


* (это пост в моем анемичном небольшом блоге)


2

В настоящее время есть два способа сделать это

  1. используя splice ()

    arrayObject.splice(index, 1);

  2. используя удалить

    delete arrayObject[index];

Но я всегда предлагаю использовать соединение для объектов массива и удалять для атрибутов объектов, потому что удаление не обновляет длину массива.


1

Хорошо, представьте, что у нас есть этот массив ниже:

const arr = [1, 2, 3, 4, 5];

Давайте сначала удалим:

delete arr[1];

и вот результат:

[1, empty, 3, 4, 5];

пустой! и давайте получим это:

arr[1]; //undefined

Значит, означает просто удаленное значение, и оно не определено сейчас, поэтому длина такая же, и она вернет true ...

Давайте сбросим наш массив и на этот раз сделаем это со сращиванием:

arr.splice(1, 1);

и вот результат на этот раз:

[1, 3, 4, 5];

Как видите, длина массива изменилась и теперь arr[1]равна 3 ...

Также это вернет удаленный элемент в массиве, который [3]в этом случае ...


1

Другие уже правильно по сравнению deleteсsplice .

Другое интересное сравнение - deleteсравнение undefined: удаленный элемент массива использует меньше памяти, чем тот, который только что установлен undefined;

Например, этот код не будет завершен:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

Это выдает эту ошибку:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

Итак, как видите, на undefinedсамом деле занимает кучу памяти.

Однако, если вы также deleteиспользуете ary-item (вместо того, чтобы просто установить его undefined), код будет медленно завершаться:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

Это крайние примеры, но они указывают на deleteто, что я нигде не видел упоминаний.


1

Если у вас небольшой массив, вы можете использовать filter:

myArray = ['a', 'b', 'c', 'd'];
myArray = myArray.filter(x => x !== 'b');

0

Самый простой способ, вероятно,

var myArray = ['a', 'b', 'c', 'd'];
delete myArray[1]; // ['a', undefined, 'c', 'd']. Then use lodash compact method to remove false, null, 0, "", undefined and NaN
myArray = _.compact(myArray); ['a', 'c', 'd'];

Надеюсь это поможет. Ссылка: https://lodash.com/docs#compact


1
Если кто-то споткнется об этом, задаваясь вопросом о compact... не нужно Лодаш. ПопробуйтеmyArray.filter(function(n){return n;})
Даты

0

Для тех, кто хочет использовать Lodash, можно использовать: myArray = _.without(myArray, itemToRemove)

Или как я использую в Angular2

import { without } from 'lodash';
...
myArray = without(myArray, itemToRemove);
...

0

delete : delete удалит свойство объекта, но не переиндексирует массив или не обновит его длину. Это заставляет это казаться, как будто это не определено:

splice : фактически удаляет элемент, переиндексирует массив и изменяет его длину.

Удалить элемент из последнего

arrName.pop();

Удалить элемент из первого

arrName.shift();

Удалить из середины

arrName.splice(starting index,number of element you wnt to delete);

Ex: arrName.splice(1,1);

Удалить один элемент из последнего

arrName.splice(-1);

Удалить используя индексный номер массива

 delete arrName[1];

0

Если нужный элемент находится посередине (скажем, мы хотим удалить 'c', индекс которого равен 1), вы можете использовать:

var arr = ['a','b','c'];
var indexToDelete = 1;
var newArray = arr.slice(0,indexToDelete).combine(arr.slice(indexToDelete+1, arr.length))

0

IndexOfпринимает также ссылочный тип. Предположим следующий сценарий:

var arr = [{item: 1}, {item: 2}, {item: 3}];
var found = find(2, 3); //pseudo code: will return [{item: 2}, {item:3}]
var l = found.length;

while(l--) {
   var index = arr.indexOf(found[l])
      arr.splice(index, 1);
   }
   
console.log(arr.length); //1

Иначе:

var item2 = findUnique(2); //will return {item: 2}
var l = arr.length;
var found = false;
  while(!found && l--) {
  found = arr[l] === item2;
}

console.log(l, arr[l]);// l is index, arr[l] is the item you look for

-1
function deleteFromArray(array, indexToDelete){
  var remain = new Array();
  for(var i in array){
    if(array[i] == indexToDelete){
      continue;
    }
    remain.push(array[i]);
  }
  return remain;
}

myArray = ['a', 'b', 'c', 'd'];
deleteFromArray(myArray , 0);

// результат: myArray = ['b', 'c', 'd'];


@ChrisDennis почему? (без сарказма или злого умысла, это искренний вопрос)
Крис Бьер

Помимо того, что этот ответ не касается вопроса ОП
Крис Бьер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.