Проще говоря, более сложные типы Javascript будет иногда нужно использовать либо .call()
или .apply()
, в частности, код, который пытается прокси-функции и передавать аргументы или контролировать значение this
.
Если вы делаете такие вещи, вам нужно знать, как работают .call()
и .apply()
, поэтому вы можете использовать правильный метод (так как они не работают одинаково). Если вы не делаете такие типы продвинутых вещей, тогда много Javascript может быть написано без их использования.
Как вопрос интервью, я думаю, что это разумный тест на то, понимаете ли вы некоторые из более продвинутых нюансов передачи аргументов, методы вызова и обработку this
в Javascript. Если вы хотите преуспеть в этом вопросе, вам нужно будет понять как .call()
, так и .apply()
, теперь, как объяснить, что они делают и как и когда их использовать, и когда вы будете использовать один против другого.
Вся концепция this
и то, как она контролируется или установлена в Javascript, часто не понимается хорошо опытными программистами Javascript (черт возьми, я даже видел опытных разработчиков, которые не понимали этого хорошо), поэтому опросив кандидата по вещам, связанным с этим, является разумным тестом, и .call()
и .apply()
являются для него несколько центральными.
Если вы разрабатывали библиотечный или рамочный код, вы, скорее всего, будете использовать .call()
или .apply()
в своей работе.
Вот основной резюме:
Каждая функция в JavaScript, является объектом, который имеет некоторые свойства. Таким образом, помимо возможности вызвать функцию, например, func()
, вы также можете ссылаться на свойства на ней, как func.length
.
Два свойства, которые имеют каждая функция: .call()
и .apply()
. Оба они позволяют вам вызвать функцию несколькими способами, чем просто называть ее func()
.
.call()
Мы все знаем, конечно, что если вы просто хотите вызвать функцию с фиксированным числом аргументов, вы можете просто выполнить func(arg1, arg2)
, и эти аргументы будут переданы функции, но что, если вы хотите контролировать значение this
, когда вы передадите эти фиксированные аргументы? Вызов func как func(arg1, arg2)
вызовет значение this
внутри этой функции, которое должно быть установлено либо глобальному объекту, либо window
в браузере, либо если он работает в строгом режиме до undefined
. Каждый вызов функции в Javascript, такой как func(arg1, arg2)
, сбрасывает указатель this
таким образом. Это где .call()
приходит Вы можете выполнить:.
func.call(someThisValue, arg1, arg2)
И он будет делать то же самое, за исключением того, func(arg1, arg2)
это приведет this
указатель должен быть установлен на someThisValue
.
Примечание: вы также можете использовать .call()
только с одним аргументом, и он просто установит указатель this
и не будет передавать никаких аргументов.
func.call(someThisValue)
.Не()
Но что, если ваш список аргументов не фиксирован и ваши аргументы в переменном массиве длиной или массив типа объекта. Вы не можете использовать .call()
, потому что вы не можете ввести правильный оператор .call()
для каждого возможного списка аргументов. Здесь вводится .apply()
. Каноническое использование для .apply()
- это когда вы просто пытаетесь передать аргументы из другого вызова функции. Это обычное явление, когда вы проксируете другие вызовы функций, чтобы немного изменить их поведение, но все же вызывать оригинал, а оригинал имеет различные формы (так что вы точно не знаете переданные аргументы) или множество различных типов функций все вызовы проходят через этот прокси. В этом случае вы можете использовать .apply()
, часто с объектом arguments
. Вы можете увидеть пример этого в MDN polyfill for .bind()
.
Предположим, что я хочу связать какую-то существующую функцию с именем doIt()
для ведения журнала, а doIt()
имеет несколько различных способов ее вызова. Используя .apply()
, я мог бы сделать это следующим образом:
// regular function already defined in your program
function doIt(arg1, arg2) {
// do something
}
// then actual usage elsewhere in the program would be just this:
doIt("foo", "bar");
// now install a proxy that can intercept all calls to doIt() and
// add some behavior before and after
(function(origDoIt) {
// replace doIt function with my own proxy
doIt = function() {
console.log("before doIt()");
// call the original function with all the arguments and this pointer
// that were passed
var retVal = origDoIt.apply(this, arguments);
console.log("after doIt()");
return retVal;
}
})(doIt);
FYI, .apply()
может также использоваться, чтобы просто установить this
указатель, как в:
func.apply(someThisValue)
В этом конкретном случае (и только в этом случае), он работает одинаково с .call()
.
Это одно из моих любимых приложений .apply()
. Метод Math.max()
принимает переменное количество аргументов и возвращает наибольшее количество из этих аргументов. Таким образом:
Math.max(1,2,3,4)
вернет 4
.
Но, используя .apply()
, мы можем найти максимальное число в любом массиве.
var list = [999,888,777,666,555,444,333,1000];
var m = Math.max.apply(Math, list);
console.log(m); // 1000
Мы используем .apply()
, чтобы отправить весь list
массив в качестве аргументов Math.max()
поэтому он будет работать на весь массив.
Обратите внимание, когда ES6 полностью реализована повсеместно или в вашем конкретном исполнении envirionment, вы можете также использовать новый оператор распространения, чтобы сделать что-то подобное:
var list = [999,888,777,666,555,444,333,1000];
var m = Math.max(...list);
console.log(m); // 1000
, который становится своего рода стенография для того, что мы делаем с .apply()
Что вы толпите. Они разные. Различные способы обработки параметров. http://stackoverflow.com/questions/1986896/what-is-the-difference-between-call-and-apply – Daniel