Зачем вызывать apply вместо прямого вызова функции?

Глядя на исходный код raphael, g.raphael или других библиотек, я заметил, что разработчик делает что-то вроде этого:

var val = Math.max.apply(Math, data_array);

Почему бы просто не вызвать функцию напрямую, например:

var val = Math.max(data_array);

Спасибо.


person codecraig    schedule 09.05.2011    source источник
comment
Итак, я вижу, что Math.max принимает два аргумента, поэтому мой пример простого вызова Math.max(array) не сработает. Итак, я думаю, вопрос в том, как первая строка кода в моем вопросе вызывает max для каждого элемента data_array?   -  person codecraig    schedule 09.05.2011
comment
Javascript .apply и .call ftw!!   -  person Rudie    schedule 09.05.2011


Ответы (5)


Я думаю, что объяснение из Mozilla Docs описывает это хорошо:

Вы можете назначить другой объект this при вызове существующей функции. this относится к текущему объекту, вызывающему объекту. С помощью apply вы можете один раз написать метод, а затем наследовать его в другом объекте, не переписывая метод для нового объекта.

apply очень похож на call, за исключением типа аргументов, которые он поддерживает. Вы можете использовать массив аргументов вместо именованного набора параметров. При применении можно использовать литерал массива, например fun.apply(this, [name, value]), или объект Array, например fun.apply(this, new Array(name, value)).

Что касается параметров:

thisArg Определяет значение this внутри fun. Если thisArg имеет значение null или не определено, this будет глобальным объектом. В противном случае this будет равно Object(thisArg) (то есть thisArg, если thisArg уже является объектом, или String, Boolean или Number, если thisArg является примитивным значением соответствующего типа). Поэтому всегда верно, что typeof this == "object" при выполнении функции.

argsArray Массив аргументов для объекта, указывающий аргументы, с которыми должен вызываться fun, или null или undefined, если аргументы не должны предоставляться функции.

Документы дают хороший пример использования для применения. В приведенном ниже примере apply используется для создания цепочки конструктора:

function product(name, value)
{
  this.name = name;
  if (value >= 1000)
    this.value = 999;
  else
    this.value = value;
}

function prod_dept(name, value, dept)
{
  this.dept = dept;
  product.apply(this, arguments);
}
prod_dept.prototype = new product();

// since 5 is less than 1000 value is set
var cheese = new prod_dept("feta", 5, "food");

// since 5000 is above 1000, value will be 999
var car = new prod_dept("honda", 5000, "auto");

Обратите внимание, что в конструкторе prod_dept предоставленное this относится к объекту prod_dept, а arguments — это массив аргументов, переданных конструктору product.

person McStretch    schedule 09.05.2011
comment
prod_dept.prototype = new product(); эта строка вообще не обязательна, пожалуйста, уберите осложнение! - person Pratik; 03.08.2018

Math.max не принимает список по умолчанию. «apply» позволяет распаковать список по аргументам, чтобы макс работал корректно.

person Juho Vepsäläinen    schedule 09.05.2011

Зачем вызывать «применить» вместо прямого вызова функции? Давайте фрагмент:

var obj = {a: "apply"};
func.call(obj, "parameter");
function func(para) {
    if(this.a === "apply"){
        console.log('apply'); 
     }
} 

Здесь мы видим, что мы используем 'this' (контекст) внутри функции. Если мы напрямую вызываем функцию, то у нас нет никакого контекста, тогда она будет использовать window контекст, что неверно. Итак, если вы используете контекст в своей функции, используйте метод apply.

person Anshul    schedule 13.12.2013

.apply часто используется, когда намерение состоит в том, чтобы вызвать функцию с переменным числом аргументов со списком значений аргументов, например.

Функция Math.max([value1[,value2, ...]]) возвращает наибольшее из ноль или более чисел.

Math.max(10, 20); // 20
Math.max(-10, -20); // -10
Math.max(-10, 20); // 20

Метод Math.max() не позволяет передавать массив. Если у вас есть список значений, из которых вам нужно получить наибольшее значение, вы обычно вызываете эту функцию, используя Function.prototype.apply(), например

Math.max.apply(null, [10, 20]); // 20
Math.max.apply(null, [-10, -20]); // -10
Math.max.apply(null, [-10, 20]); // 20

Однако, начиная с ECMAScript 6, вы можете использовать оператор расширения spread. :

Оператор расширения позволяет расширить выражение в местах, где ожидается несколько аргументов (для вызовов функций) или несколько элементов (для литералов массива).

Math.max(...[10, 20]); // 20
Math.max(...[-10, -20]); // -10
Math.max(...[-10, 20]); // 20

При вызове функции с помощью оператора вариационного типа вы даже можете добавить дополнительные значения, например.

Math.max(...[10, 20], 50); // 50
Math.max(...[-10, -20], 50); // 50
person Gajus    schedule 18.12.2014

Как правило, вы должны использовать apply() и call(), чтобы иметь возможность установить контекст или объект, к которому принадлежит вызывающая функция. Затем функция фактически становится методом этого объекта/контекста, что полезно, если вам нужно получить доступ к полям контекста.

Вот как Javascript изначально вызывает функции:

  1. Составьте список аргументов (argList) из параметров с 1 по конец
  2. Первый параметр это значение
  3. Вызовите функцию с этим набором для thisValue и argList в качестве списка аргументов.

Ссылка: Понимание вызова функций JavaScript и "this" автор Иегуда Кац

Таким образом, при непосредственном вызове функции вы фактически неявно передаете контекст по умолчанию функции. Javascript передает 'window' или 'undefined' в качестве контекста, если вы не указываете его с помощью call() или apply()

Этот ответ также дает пример, который может помочь в понимании использования

person Saba Ahang    schedule 26.10.2015