Статьи

Распределение массивов по аргументам в JavaScript


Иногда нужно
распространять элементы массива, чтобы использовать их в качестве аргументов вызова функции. JavaScript позволяет вам делать это через Function.prototype.apply, но это не работает для вызовов конструктора. В этом посте рассказывается о распространении и о том, как заставить его работать в присутствии нового оператора.

распространение

Распространение означает выполнение вызова функции, вызова метода или конструктора и предоставление аргументов через массив. В Python это называется
распаковка . Для этой цели ECMAScript.next будет иметь
оператор распространения (префикс …). В текущем JavaScript вы можете выполнить эту операцию через Function.prototype.apply.

Пример: вызов функции. Math.max () возвращает максимум среди своих 0 или более числовых параметров. С оператором распространения вы можете использовать его для массивов:

    Math.max(...[13, 7, 30])

Это эквивалент

    Math.max(13, 7, 30)

В текущем JavaScript вы должны использовать apply ().

    > Math.max.apply(null, [13, 7, 30])
    30

Объяснение: Вызов применения выглядит следующим образом:

    func.apply(thisValue, [param1, param2, ...])

что эквивалентно

    thisValue.func(param1, param2, ...)

Обратите внимание, что func не должен быть методом thisValue — apply временно превращает его в единицу.

Пример: вызов конструктора. Конструктор Date принимает несколько числовых параметров и создает дату. С помощью оператора распространения вы можете передать массив.

    new Date(...[2011, 11, 24]) // Christmas 2011

Однако apply не работает с конструкторами, поскольку оператор new предполагает, что конечный вызов метода apply
является конструктором. Следующее является обходным путем:

    new (Function.prototype.bind.apply(
        Date, [null].concat([2011, 11, 24])))

Что здесь происходит? Давайте посмотрим на основные компоненты:

  • bind: мы используем этот метод, чтобы превратить Date в функцию с нулевыми параметрами, предварительно заполнив их. Вызов bind выглядит следующим образом:
        func.bind(thisValue, [arg1], [arg2], ...)
    

    Он превращает func в новую функцию, для которой неявным параметром this является thisValue и чьи начальные аргументы всегда соответствуют заданным Когда кто-то вызывает новую функцию, аргументы такого вызова добавляются к тому, что уже было предоставлено через bind. У MDN есть больше деталей . То, что мы хотим сделать, это следующее.

        Date.bind(null, ...[2011, 11, 24])
    

    Первый аргумент является нулевым, потому что bind превращает Date в функцию, которая не нуждается в thisValue: он вызывается только как конструктор, а new переопределяет thisValue из bind. Чтобы смоделировать вышеупомянутый оператор распространения, нам нужен метод apply.

  • apply: опять же, мы используем apply, чтобы превратить массив в аргументы для вызова функции. Мы вызываем apply для функции Function.prototype.bind с двумя аргументами:

    • 1-й аргумент: имеет значение Date
    • 2-й аргумент: аргументы для привязки создаются путем добавления нулевого значения к массиву [2011, 11, 24]. Мы используем немного более многословный конкат вместо unshift, потому что он неразрушающий (не меняет это).

    Выполненный вызов метода, таким образом,

        Date.bind(null, 2011, 11, 24)
    

    что совпадает с вышеупомянутым Date.bind (null, … [2011, 11, 24]).

  • new: Вызвать функцию с нулевым аргументом, созданную bind, как конструктор. Помещая операнд в скобки, мы избегаем применения становления конструктором и вместо этого используем новый в результате применения.

Распространение конструктора через библиотечный метод

Mozilla предлагает превратить вышеуказанное решение в библиотечный метод. Ниже приведена слегка отредактированная версия
их предложения :

    if (!Function.prototype.construct) {
        Function.prototype.construct = function(argArray) {
            if (! Array.isArray(argArray)) {
                throw new TypeError("Argument must be an array");
            }
            var nullaryFunc = Function.prototype.bind.apply(
                this, [null].concat(argArray));
            return new nullaryFunc();
        };
    }

Взаимодействие:

    > Date.construct([2011, 11, 24])
    Sat Dec 24 2011 00:00:00 GMT+0100 (CET)

 

С http://www.2ality.com/2011/08/spreading.html