В этом блоге описаны три хитрости для работы с массивами с помощью apply.
Метод применения
применить это метод, который есть у всех функций. Его подпись
func.apply(thisValue, [arg1, arg2, ...])
Игнорируя thisValue, приведенный выше вызов эквивалентен:
func(arg1, arg2, ...)
Таким образом, apply позволяет нам разворачивать массив «в» аргументы вызова функции. Давайте рассмотрим три уловки, которые позволяют нам выполнить.
Трюк 1: передать массив функции, которая не принимает массивы
В JavaScript нет функции, которая возвращает максимум массива чисел. Однако есть функция Math.max, которая работает с произвольным числом числовых аргументов. Благодаря применению, мы можем использовать эту функцию для наших целей:
> Math.max.apply(null, [10, -1, 5]) 10
Трюк 2: устранить дыры в массивах
Отверстия в массивах
Краткое напоминание: в JavaScript массив представляет собой карту из чисел в значения. Таким образом, существует разница между отсутствующим элементом (отверстием) и элементом со значением undefined
[1] . Первый пропускается итерационными методами Array.prototype (forEach, map и т. Д.), Последний — нет:
> ["a",,"b"].forEach(function (x) { console.log(x) }) a b > ["a",undefined,"b"].forEach(function (x) { console.log(x) }) a undefined b
Вы также можете проверить наличие отверстий с помощью оператора in.
> 1 in ["a",,"b"] false > 1 in ["a", undefined, "b"] true
Но если вы прочитаете отверстие, результат будет неопределенным как для отверстий, так и для неопределенных элементов.
> ["a",,"b"][1] undefined > ["a", undefined, "b"][1] undefined
Устранение дыр
С помощью apply и Array (которые можно использовать как функцию или конструктор) вы можете превратить отверстия в неопределенные элементы:
> Array.apply(null, ["a",,"b"]) [ 'a', undefined, 'b' ]
Вышеприведенное работает, потому что apply не игнорирует дыры, а передает их как неопределенные аргументы функции:
> function returnArgs() { return [].slice.call(arguments) } > returnArgs.apply(null, ["a",,"b"]) [ 'a', undefined, 'b' ]
Увы, вы столкнулись с причудой здесь. Если Array получает один числовой аргумент, создается пустой массив, длина которого равна числу
[2] :
> Array.apply(null, [ 3 ]) [ , , ]
Поэтому, если вам нужна эта функциональность, лучше написать свою собственную функцию:
function fillHoles(arr) { var result = []; for(var i=0; i < arr.length; i++) { result[i] = arr[i]; } return result; }
Пример:
> fillHoles(["a",,"b"]) [ 'a', undefined, 'b' ]
Подчеркивание дает вам
функцию _.compact, которая удаляет все ложные значения, включая дыры:
> _.compact(["a",,"b"]) [ 'a', 'b' ] > _.compact(["a", undefined, "b"]) [ 'a', 'b' ] > _.compact(["a", false, "b"]) [ 'a', 'b' ]
Трюк 3: сгладить массив
Задача: превратить массив массивов с элементами в просто массив элементов. Опять же, мы используем возможность развернуть apply, чтобы concat сделал эту работу за нас:
> Array.prototype.concat.apply([], [["a"], ["b"]]) [ 'a', 'b' ]
Элементы не-массива добавляются как:
> Array.prototype.concat.apply([], [["a"], "b"]) [ 'a', 'b' ]
applyS thisValue должно быть здесь [], потому что concat — это метод, а не не-метод. Выполняется только один уровень выравнивания:
> Array.prototype.concat.apply([], [[["a"]], ["b"]]) [ [ 'a' ], 'b' ]
Если вы хотите, чтобы ваш код был информативным, вам следует рассмотреть альтернативные варианты, в том числе реализовать собственную функцию с правильным именем. У Underscore есть _.flatten, который обрабатывает любой уровень вложенности:
> _.flatten([[["a"]], ["b"]]) [ 'a', 'b' ]