В 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>.