В JavaScript функция тоже является объектом – объектом Function и тоже имеет прототип, свойства, методы, в том числе мощные методы call()
и apply()
. Эти методы позволяют вызывать функцию так, будто она является методом некоторого объекта. Первый аргумент методов call()
и apply()
– это объект, для которого выполняется функция. Этот аргумент становится значением ключевого слова this
в теле функции.
Метод call()
Метод call() вызывает функцию с указанным значением this
и индивидуально предоставленными аргументами. Первый аргумент служит контекстом вызова и становится значением ключевого слова this
в теле функции. Все оставшиеся аргументы call() – это значения, передаваемые вызываемой функции.
func.call(context, arg1, arg2, ...)
Начнем со следующего кода:
Первый вызов fun() отобразит значение 10, так как this
ссылается на глобальный объект Window
. Второй вызов (через метод call
), отобразит значение 15. 15 – это значение свойства x внутри объекта obj. Здесь метод call()
используется для вызова fun() (метода) от имени объекта obj.
После контекста в методе call
можно передать аргументы для вызываемой функции:
При помощи call
вы можете использовать метод, принадлежащий одному объекту, а вызвать его в контексте другого:
Метод apply()
Метод apply()
идентичен call()
, за исключением того, что apply() требует, чтобы в качестве второго параметра был выбран массив (либо массивоподобный объект). Массив представляет аргументы для целевого метода.
func.call(context, arg1, arg2);
// идентичен вызову
func.apply(context, [arg1, arg2]);
// или
func.apply(context, new Array(arg1, arg2));
Метод apply()
полезен, если у вас есть массив и вы хотите использовать его значения как аргументы функции, для которых в противном случае пришлось бы писать цикл по массиву значений. Классический пример – поиск минимального или максимального числа в массиве. Вспомогательным функциям Math.max()/Math.min()
можно передать любое количество аргументов, а они возвращают минимальное или максимальное значение, соответственно. Мы можем использовать метод apply()
, чтобы вызвать эти функции с существующим массивом:
Обратите внимание, что вместо значения this
мы просто передаем null
. В данном случае в качестве контекста можно передавать что угодно, поскольку в своей внутренней реализации методы Math.max
и не Math.min
использует this
вообще.
Обратите внимание, что this
в методах call()
и apply()
может не быть реальным значением, видимым этим методом. Если метод является функцией в нестрогом режиме (без use strict), значения null
и undefined
будут заменены глобальным объектом (this = window
), а примитивные значения будут упакованы в объекты:
В качестве второго параметра метода apply()
вы также можете использовать псевдомассив arguments
. Каждая функция имеет специальную локальную переменную arguments
, доступную внутри её области применения. Псевдомассив arguments
может использоваться для всех неопределённых аргументов вызываемого объекта. Вы можете даже не знать, сколько и какие аргументы будет требать вызываемый объект при использовании метода apply()
. Таким образом, вы можете использовать arguments
для передачи всех аргументов в вызываемый объект. Мнтерпретатор JavaScript самостоятельно разберётся с обработкой аргументов.
Чтобы исследовать свойства arguments
, давайте создадим тестирующую функцию:
Здесь свойство callee
псевдомассива arguments
хранит ссылку на функцию-родитель.
Несмотря на то, что arguments
выглядит как массив, но это всё же объект. Однако во многих случаях хотелось бы манипулировать им, как если бы это был массив. Чтобы превратить arguments
в массив, воспользуемся следующим приёмом: возьмём метод массива slice
.
Вызов arr.slice(start, end)
возвращает новый массив, содержащий копию части исходного массива. start – индекс элемента в массиве arr, с которого будет начинаться новый массив; end – индекс элемента в массиве arr, на котором новый массив завершится. А если start и end не указаны, то копирует весь массив.
arguments
:
Здесь вызов Array.prototype.slice() скопирует все элементы из this (arguments) в новый массив.
Стоит отметить, что вместо Array.prototype вы можете задать пустой массив как [] или new Array(): [].slice.call(arguments)|new Array().slice.call(arguments).
Итоги
- Методы
call
иapply
позволяют вызывать функцию так, будто она является методом некоторого объекта. - Первый аргумент передоваемый методами
call
иapply
служит контекстом вызова и становится значением ключевого словаthis
в теле функции. - После контекста (
this
) в методеcall
можно передать аргументы для вызываемой функции. - При помощи
call
иapply
вы можете использовать метод, принадлежащий одному объекту, а вызвать его в контексте другого. - Метод
apply
идентиченcall
, за исключением того, чтоapply
требует, чтобы в качестве второго параметра был выбран массив (либо массивоподобный объект). Массив представляет аргументы для целевого метода.
Задачи
-
Счетчик превысил заданное число
Напишите функцию getMax(fn, num), которая принимает функцию и число num. Функция getMax должна возвращать функцию, которая при каждом вызове увеличивает свой внутренний счетчик (
counter++
). Если счетчик больше числа num, внутренняя функция должна возвращать строку «Максимум!»,function add(a,b){ return a+b } function getMax(fn, num) { /* ваш код */ } var addOnlyThreeTimes = getMax(add, 3); addOnlyThreeTimes(1,2) // 3 addOnlyThreeTimes(2,2) // 4 addOnlyThreeTimes(1,2) // 3 addOnlyThreeTimes(1,2) // "Максимум!"
Решение:
-
Вывести сумму четных чисел
Напишите функцию sumEvenArguments, которая принимает все аргументы, переданные ей при вызове, и возвращает сумму четных чисел (из числа аргументов).
sumEvenArguments(1,2,3,6) // 8 sumEvenArguments(1,12,6) // 18 sumEvenArguments(1,2) // 2 // ваш код
-
Комментарии
<code>
, несколько строчек кода — в теги<pre><code>
...ваш код...</code></pre>
.