Общие сведения
Метод apply()
вызывает функцию с указанным значением this
и аргументами, предоставленными в виде массива (либо массивоподобного объекта).
Примечание: хотя синтаксис этой функции практически полностью идентичен функции call()
, фундаментальное различие между ними заключается в том, что функция call()
принимает список аргументов, в то время, как функция apply()
принимает единичный массив аргументов.
Синтаксис
fun.apply(thisArg[, argsArray])
Параметры
thisArg
- Значение
this
, предоставляемое для вызова функцииfun
. Обратите внимание, чтоthis
может не быть реальным значением, видимым этим методом: если метод является функцией в нестрогом режиме, значенияnull
иundefined
будут заменены глобальным объектом, а примитивные значения будут упакованы в объекты. argsArray
- Массивоподобный объект, определяющий аргументы, с которыми функция
fun
должна быть вызвана, либоnull
илиundefined
, если в функцию не надо передавать аргументы. Начиная с ECMAScript 5 эти аргументы могут быть обобщёнными массивоподобными объектами, а не только массивом. Смотрите ниже информацию по совместимости с браузерами.
Описание
Вы можете присваивать различные объекты this
при вызове существующей функции. this
ссылается на текущий объект, вызывающий объект. С помощью apply()
вы можете написать метод один раз, а затем наследовать его в других объектах без необходимости переписывать метод для каждого нового объекта.
Метод apply
очень похож на метод call()
, за исключением поддерживаемого типа аргументов. Вы можете использовать массив аргументов вместо набора именованных параметров. Вместе с apply
вы можете использовать литерал массива, например, fun.apply(this, ['есть', 'бананы'])
, либо объект Array
, например, fun.apply(this, new Array('есть', 'бананы'))
.
Также вы можете использовать в качестве параметра argsArray
псевдомассив arguments
. arguments
является локальной переменной функции. Он может использоваться для всех неопределённых аргументов вызываемого объекта. Таким образом, вы не обязаны знать, сколько и какие аргументы требует вызываемый объект при использовании метода apply()
. Вы можете использовать псевдомассив arguments
для передачи всех аргументов в вызываемый объект. Вызываемый объект самостоятельно разберётся с обработкой аргументов.
Начиная с 5-го издания ECMAScript, вы также можете использовать любой вид массивоподобного объекта, что на практике означает, что он должен иметь свойство length
и целочисленные свойства в диапазоне (0...length)
. В качестве примера, теперь вы можете использовать NodeList
или свой собственный объект вида { 'length': 2, '0': 'есть', '1': 'бананы' }
.
Примеры
Пример: использование apply()
для связи конструкторов объекта в цепочку
Вы можете использовать метод apply()
для объединения в цепочку конструкторов объекта, как в Java. В следующем примере мы создадим в объекте Function
глобальный метод construct()
, который позволит нам использовать массивоподобные объекты с конструктором вместо списка аргументов.
Function.prototype.construct = function (aArgs) { var oNew = Object.create(this.prototype); this.apply(oNew, aArgs); return oNew; };
Примечание: метод Object.create()
, использованный в этом примере, относительно новый. В качестве альтернативного способа можно рассмотреть возможность использования замыкания:
Function.prototype.construct = function(aArgs) { var fConstructor = this, fNewConstr = function() { fConstructor.apply(this, aArgs); }; fNewConstr.prototype = fConstructor.prototype; return new fNewConstr(); };
Пример использования:
function MyConstructor() { for (var nProp = 0; nProp < arguments.length; nProp++) { this['property' + nProp] = arguments[nProp]; } } var myArray = [4, 'Привет, мир!', false]; var myInstance = MyConstructor.construct(myArray); alert(myInstance.property1); // выведет 'Привет, мир!' alert(myInstance instanceof MyConstructor); // выведет 'true' alert(myInstance.constructor); // выведет 'MyConstructor'
Примечание: этот неродной метод Function.construct()
не будет работать с некоторыми родными конструкторами (вроде конструктора Date
, к примеру). В этих случаях вы можете использовать метод Function.prototype.bind()
(например, представьте, что вы имеете следующий массив, который можно использовать с конструктором Date
: [2012, 11, 4]
; в этом случае вы напишите что-то вроде: new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))()
— так или иначе, это не самый изящный способ и, вероятно, его не стоит использовать в рабочем окружении).
Пример: использование apply()
и встроенных функций
Умное использование метода apply()
позволяет вам использовать встроенные функции для некоторых задач, для которых в противном случае пришлось бы писать цикл по массиву значений. В качестве примера давайте используем Math.max()
/Math.min()
для нахождения максимального/минимального значения в массиве.
/* мин/макс числа в массиве */ var numbers = [5, 6, 2, 3, 7]; /* используем apply к Math.min/Math.max */ var max = Math.max.apply(null, numbers); /* Это эквивалентно Math.max(numbers[0], ...) или Math.max(5, 6, ...) */ var min = Math.min.apply(null, numbers); /* сравним с простым алгоритмом с циклом */ max = -Infinity, min = +Infinity; for (var i = 0; i < numbers.length; i++) { if (numbers[i] > max) { max = numbers[i]; } if (numbers[i] < min) { min = numbers[i]; } }
Но будьте осторожны: при использовании метода apply()
таким образом вы рискуете выйти за пределы ограничения на количество аргументов в движке JavaScript. Последствия применения функции с очень большим количеством аргументов (думается, больше десяти тысяч аргументов) различаются от движка к движку (JavaScriptCore имеет жёстко зашитое ограничение на количество аргументов в 65536), поскольку этот предел (на самом деле, это природа поведения любого чрезвычайно огромного стека) не определён. Некоторые движки будут выкидывать исключение. Хуже того, другие просто отбрасывают реально переданные функции аргументы сверх лимита. (Для иллюстрации последнего случая: если такой движок имеет ограничение в четыре элемента [реальное ограничение, конечно же, гораздо выше], это выглядело бы так, как если бы в примере выше в метод apply()
были переданы аргументы 5, 6, 2, 3
, а не весь массив.) Если ваш масив значений может вырасти до десятков тысяч, используйте смешанный подход: применяйте вашу функцию к порциям массива:
function minOfArray(arr) { var min = Infinity; var QUANTUM = 32768; for (var i = 0, len = arr.length; i < len; i += QUANTUM) { var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len))); min = Math.min(submin, min); } return min; } var min = minOfArray([5, 6, 2, 3, 7]);
Пример: использование apply()
в «monkey-патчинге»
Метод apply()
может быть лучшим вариантом для «monkey-патчинга» встроенных в Firefox функций, либо JS библиотек. Пусть у вас есть функция someobject.foo()
, вы можете изменить её таким немного хакерским способом:
var originalfoo = someobject.foo; someobject.foo = function() { // Делаем что-то до вызова функции console.log(arguments); // Вызываем функцию так, как будто бы она была вызвана обычным образом: originalfoo.apply(this, arguments); // Делаем что-то после вызова функции. }
Этот метод особенно удобен, когда вам нужно отладить события, либо интерфейс с чем-то, что не имеет API, вроде различных событий .on([event]...
, например, тех что используются в Инспекторе инструментов разработчика).
Спецификации
Спецификация | Статус | Комментарии |
---|---|---|
ECMAScript 3-е издание. | Стандарт | Изначальное определение. Реализована в JavaScript 1.3. |
ECMAScript 5.1 (ECMA-262) Определение 'Function.prototype.apply' в этой спецификации. |
Стандарт | |
ECMAScript 2015 (6th Edition, ECMA-262) Определение 'Function.prototype.apply' в этой спецификации. |
Стандарт |
Совместимость с браузерами
Возможность | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Базовая поддержка | (Да) | (Да) | (Да) | (Да) | (Да) |
Обобщённые массивоподобные объекты ES 5.1, вроде arguments |
? | 4.0 (2.0) | ? | ? | ? |
Возможность | Android | Chrome для Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Базовая поддержка | (Да) | (Да) | (Да) | (Да) | (Да) | (Да) |
Обобщённые массивоподобные объекты ES 5.1, вроде arguments |
? | ? | 4.0 (2.0) | ? | ? | ? |