Эта статья принадлежит базовым навыкам JavaScript. Мы узнаем различные общие методы объединения/объединения двух массивов JS и сравнить преимущества и недостатки различных методов.
Давайте посмотрим на конкретный сценарий:
Кода -копия выглядит следующим образом:
var q = [5, 5, 1, 9, 9, 6, 4, 5, 8];
var b = ["tie", "mao", "csdn", "ren", "fu", "fei"];
Очевидно, что результат простого сплайсинга массивов Q и B - это:
Кода -копия выглядит следующим образом:
[
5, 5, 1, 9, 9, 6, 4, 5, 8,
"Tie", "Mao", "csdn", "ren", "fu", "fei"
]
CONCAT (..) Метод
Наиболее распространенные использование заключается в следующем:
Кода -копия выглядит следующим образом:
var c = q.concat (b);
Q; // [5,5,1,9,9,6,4,5,8]
б; // ["tie", "mao", "csdn", "ren", "fu", "fei"];
c; // [5,5,1,9,9,6,4,5,8, "TIE", "MAO", "CSDN", "ren", "fu", "fei"]
Как видите, C - это совершенно новый массив, который представляет собой комбинацию из двух массивов: Q и B, но Q и B теперь бесполезны, верно?
Если у массива Q есть 10 000 элементов, а у массива B есть 10 000 элементов? Затем в массиве C теперь есть 20 000 элементов, которые занимают вдвое больше памяти.
«Это нормально!» - вы можете подумать. Просто поместите Q и B напрасно, а затем это будет собирать мусор, верно? Проблема решена!
Кода -копия выглядит следующим образом:
q = b = null; // `Q` и` b` теперь могут быть собраны мусором
Гм? Если массивы маленькие, то, естественно, нет проблем. Однако, когда требуются большие массивы или повторная обработка, память ограничена, и ее также необходимо оптимизировать.
Вставка петли
Хорошо, давайте попробуем добавить содержимое массива в другой, используя метод массива#push ():
Кода -копия выглядит следующим образом:
// вставьте массив `b` в` Q`
for (var i = 0; i <b.length; i ++) {
Q.push (b [i]);
}
Q; // [5,5,1,9,9,6,4,5,8, "TIE", "MAO", "CSDN", "ren", "fu", "fei"]
b = null;
Теперь содержимое двух оригинальных массивов хранится в Q (Q + B).
Похоже, что это хорошо справилось с оптимизацией памяти.
Но что, если массив Q очень маленький, а B очень большой? Для соображений памяти и скорости вы хотите вставить меньший Q в переднюю часть b. Нет проблем, просто используйте метод unshift () вместо push (), и соответствующий обход должен выполняться от больших до малого:
Кода -копия выглядит следующим образом:
// `Q` в` b`:
for (var i = q.length-1; i> = 0; i--) {
b. unhift (q [i]);
}
б; // [5,5,1,9,9,6,4,5,8, "TIE", "MAO", "CSDN", "ren", "fu", "fei"]
q = null;
Практические советы
К сожалению, для петли деревенский и трудный для поддержания. Можем ли мы сделать лучше?
Давайте попробуем массив#Сначала уменьшить:
Кода -копия выглядит следующим образом:
// `b` на` Q`:
q = b.reduce (function (coll, item) {
coll.push (item);
вернуть колл;
}, q);
Q; // [5,5,1,9,9,6,4,5,8, "TIE", "MAO", "CSDN", "ren", "fu", "fei"]
// или `Q` в` b`:
b = Q.reduceright (function (coll, item) {
coll.unshift (item);
вернуть колл;
}, b);
б; // [5,5,1,9,9,6,4,5,8, "TIE", "MAO", "CSDN", "ren", "fu", "fei"]
Array#Reduct () и Array#Reduceright () очень высокие, но немного громоздкие, и большинство людей не могут вспомнить. Функции со стрелками => со стрелками (функции стрел) в спецификации JS 6 могут значительно уменьшить количество кода, но для каждого элемента массива требуется функциональные вызовы, что также является очень плохим методом.
Так как насчет следующего кода?
Кода -копия выглядит следующим образом:
// `b` на` Q`:
Q.push.apply (q, b);
Q; // [5,5,1,9,9,6,4,5,8, "TIE", "MAO", "CSDN", "ren", "fu", "fei"]
// или `Q` в` b`:
b.unshift.apply (b, q);
б; // [5,5,1,9,9,6,4,5,8, "TIE", "MAO", "CSDN", "ren", "fu", "fei"]
Большой выше, верно!? В частности, метод Unshift () не должен рассматривать противоположный порядок, как и раньше. Оператор расширения ES6 (оператор спреда, префикс) более продвинут: A.Push (... B) или B.UNSHIFT (... A)
Однако на самом деле этот метод все еще слишком оптимистичен. В обоих случаях, независимо от того, должно ли это пройти a или b, чтобы применить () в качестве второго параметра (первый параметр становится этим внутренне при вызове функции применения в методе применения, то есть контекст, объем) или ... Метод оператора расширения, массив фактически будет разбит на аргументы функции.
Первая серьезная проблема заключается в том, что он занимает двойную память (конечно, временно!), Поскольку массив должен быть скопирован в стек функций. Кроме того, различные двигатели JS имеют разные алгоритмы реализации, которые могут ограничить количество параметров, которые может пройти функция.
Если массив добавляет миллион элементов, он определенно превысит размер, разрешенный стеком функций, будь то push () или вызов unshift (). Этот метод доступен только в том случае, когда есть несколько тысяч элементов, поэтому он должен быть ограничен превышением определенного диапазона.
Примечание. Вы также можете попробовать Splice (), и вы обязательно обнаружите, что он имеет такое же ограничение, что и Push (..)/unshift (..).
Одним из вариантов является продолжение использования этого метода, но при переработке партии:
Кода -копия выглядит следующим образом:
функция CombineInto (Q, B) {
var len = q.length;
for (var i = 0; i <len; i = i+5000) {
// 5000 предметов обрабатываются одновременно
b.unshift.apply (b, Q.slice (i, i+5000));
}
}
Подождите, мы ставим под угрозу читаемость кода (даже производительность!). Завершите это путешествие, прежде чем мы сдамся.
Суммировать
Array#Concat () - это проверенный и протестированный метод объединения двух (или более) массивов. Но он создает новый массив вместо того, чтобы изменить существующий.
Есть много способов адаптации, но все они имеют разные преимущества и недостатки, и они должны быть выбран в соответствии с фактическими условиями.
Различные преимущества/недостатки перечислены выше, и, возможно, лучшие (включая тех, которые не перечислены), методы являются уменьшенные (..) и редуксерист (..)
Что бы вы ни выбрали, вы должны критически думать о своей комбинации и стратегии, а не воспринимать ее как должное.