В чем разница между призывом и подачей заявки?

В чем разница между использованием call и apply для вызова функции?

var func = function() {
  alert('hello!');
};

func.apply(); vs func.call();

Существуют ли различия в производительности между двумя вышеупомянутыми методами? Когда лучше использовать call over apply и наоборот?

Ответы

Ответ 1

Разница в том, что apply позволяет вам вызывать функцию с arguments в виде массива; call требует, чтобы параметры были указаны явно. Полезной мнемоникой является "A для a Rray и C для c omma."

См. документацию MDN по заявке и звонку.

Псевдосинтаксис:

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

Начиная с ES6, есть также возможность spread массива для использования с функцией call, вы можете увидеть совместимость здесь.

Пример кода:

function theFunction(name, profession) {
    console.log("My name is " + name + " and I am a " + profession +".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator

Ответ 2

К. Скотт Аллен хорошая запись по этому вопросу.

В основном, они отличаются тем, как они обрабатывают аргументы функции.

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

Итак:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);

Ответ 3

Чтобы ответить на вопрос о том, когда использовать каждую функцию, используйте apply, если вы не знаете числа аргументов, которые вы передадите, или если они уже находятся в массиве или подобном массиву объекте (например, t21 > object для пересылки ваших собственных аргументов. Используйте call иначе, так как нет необходимости обертывать аргументы в массиве.

f.call(thisObject, a, b, c); // Fixed number of arguments

f.apply(thisObject, arguments); // Forward this function arguments

var args = [];
while (...) {
    args.push(some_value());
}
f.apply(thisObject, args); // Unknown number of arguments

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

Не должно быть никаких различий в производительности, кроме, может быть, если вы используете apply и завершаете аргументы в массиве (например, f.apply(thisObject, [a, b, c]) вместо f.call(thisObject, a, b, c)). Я не тестировал его, поэтому могут быть различия, но это было бы очень специфично для браузера. Вероятно, call быстрее, если у вас еще нет аргументов в массиве, а apply быстрее, если вы это сделаете.

Ответ 4

Здесь хорошая мнемоника. A pply использует A rrays и A всегда принимает один или два аргумента. Когда вы используете C все, что вам нужно C, укажите количество аргументов.

Ответ 5

Пока это старая тема, я просто хотел указать, что .call немного быстрее, чем .apply. Я не могу точно сказать, почему.

См. jsPerf, http://jsperf.com/test-call-vs-apply/3


[UPDATE!]

Дуглас Крокфорд кратко упоминает разницу между ними, что может помочь объяснить разницу в производительности... http://youtu.be/ya4UHuXNygM?t=15m52s

Применить принимает массив аргументов, в то время как Call принимает нулевые или более отдельные параметры! Ах, ха!

.apply(this, [...])

.call(this, param1, param2, param3, param4...)

Ответ 6

Далее следует выдержка из книги "Закрытие: полное руководство" Майкла Болина. Это могло бы выглядеть немного длинным, но это пропитало много понимания. Из "Приложения Б. Часто неверно понимаемые концепции JavaScript":


К чему this относится, когда вызывается функция

При вызове функции вида foo.bar.baz() объект foo.bar называется получателем. Когда функция вызывается, это получатель, который используется в качестве значения для this:

var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
  for (var i = 0; i < arguments.length; i++) {
    this.value += arguments[i];
  }
  return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);

Если нет явного получателя при вызове функции, тогда глобальный объект становится получателем. Как объяснено в "goog.global" на странице 47, окно - это глобальный объект, когда JavaScript выполняется в веб-браузере. Это приводит к неожиданному поведению:

var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN

Несмотря на то, что obj.addValues и f ссылаются на одну и ту же функцию, при вызове они ведут себя по-разному, потому что значение получателя различается при каждом вызове. По этой причине при вызове функции, которая ссылается на this, важно убедиться, что this будет иметь правильное значение при вызове. Для ясности, если бы на this не ссылались в теле функции, то поведение f(20) и obj.addValues(20) было бы одинаковым.

Поскольку функции являются первоклассными объектами в JavaScript, они могут иметь свои собственные методы. Все функции имеют методы call() и apply() которые позволяют переопределить получатель (т.е. Объект, к которому this относится) при вызове функции. Подписи метода следующие:

/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;

Обратите внимание, что единственное различие между call() и apply() состоит в том, что call() получает параметры функции в виде отдельных аргументов, тогда как apply() получает их как один массив:

// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);

Следующие вызовы эквивалентны, так как f и obj.addValues ссылаются на одну и ту же функцию:

obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);

Однако, поскольку ни call() ни apply() используют значение своего собственного получателя для замены аргумента получателя, когда он не указан, следующее не будет работать:

// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);

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

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


Конец выписки.

Ответ 7

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

Пример небольшого кода:

var friend = {
    car: false,
    lendCar: function ( canLend ){
      this.car = canLend;
 }

}; 

var me = {
    car: false,
    gotCar: function(){
      return this.car === true;
  }
};

console.log(me.gotCar()); // false

friend.lendCar.call(me, true); 

console.log(me.gotCar()); // true

friend.lendCar.apply(me, [false]);

console.log(me.gotCar()); // false

Эти методы очень полезны для предоставления временных объектов объектов.

Ответ 8

Другой пример с Call, Apply и Bind. Разница между Call и Apply очевидна, но Bind работает следующим образом:

  • Bind возвращает экземпляр функции, которая может быть выполнена
  • Первый параметр 'this'
  • Второй параметр - список аргументов, разделенных запятыми (например, Call)

}

function Person(name) {
    this.name = name; 
}
Person.prototype.getName = function(a,b) { 
     return this.name + " " + a + " " + b; 
}

var reader = new Person('John Smith');

reader.getName = function() {
   // Apply and Call executes the function and returns value

   // Also notice the different ways of extracting 'getName' prototype
   var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
   console.log("Apply: " + baseName);

   var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy"); 
   console.log("Call: " + baseName);

   // Bind returns function which can be invoked
   var baseName = Person.prototype.getName.bind(this, "is a", "boy"); 
   console.log("Bind: " + baseName());
}

reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/

Ответ 9

Я хотел бы показать пример, где используется аргумент valueForThis:

Array.prototype.push = function(element) {
   /*
   Native code*, that uses 'this'       
   this.put(element);
   */
}
var array = [];
array.push(1);
array.push.apply(array,[2,3]);
Array.prototype.push.apply(array,[4,5]);
array.push.call(array,6,7);
Array.prototype.push.call(array,8,9);
//[1, 2, 3, 4, 5, 6, 7, 8, 9] 

** подробнее: http://es5.github.io/#x15.4.4.7 *

Ответ 10

Call() принимает разделенные запятыми аргументы, ex:

.call(scope, arg1, arg2, arg3)

и apply() принимает массив аргументов, ex:

.apply(scope, [arg1, arg2, arg3])

Вот несколько примеров использования: http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/

Ответ 11

Из документы MDN в Function.prototype.apply():

Метод apply() вызывает функцию с заданным значением this и аргументы, предоставленные в виде массива (или подобный массиву объект).

Синтаксис

fun.apply(thisArg, [argsArray])

Из документы MDN в Function.prototype.call():

Метод call() вызывает функцию с заданным значением this и аргументами, предоставленными индивидуально.

Синтаксис

fun.call(thisArg[, arg1[, arg2[, ...]]])

От Function.apply и Function.call в JavaScript:

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


Пример кода:

var doSomething = function() {
    var arr = [];
    for(i in arguments) {
        if(typeof this[arguments[i]] !== 'undefined') {
            arr.push(this[arguments[i]]);
        }
    }
    return arr;
}

var output = function(position, obj) {
    document.body.innerHTML += '<h3>output ' + position + '</h3>' + JSON.stringify(obj) + '\n<br>\n<br><hr>';
}

output(1, doSomething(
    'one',
    'two',
    'two',
    'one'
));

output(2, doSomething.apply({one : 'Steven', two : 'Jane'}, [
    'one',
    'two',
    'two',
    'one'
]));

output(3, doSomething.call({one : 'Steven', two : 'Jane'},
    'one',
    'two',
    'two',
    'one'
));

Ответ 12

Основное отличие состоит в том, что call() принимает список аргументов , а apply() принимает один массив аргументов.

Ответ 13

Здесь небольшая почта, я написал об этом:

http://sizeableidea.com/call-versus-apply-javascript/

var obj1 = { which : "obj1" },
obj2 = { which : "obj2" };

function execute(arg1, arg2){
    console.log(this.which, arg1, arg2);
}

//using call
execute.call(obj1, "dan", "stanhope");
//output: obj1 dan stanhope

//using apply
execute.apply(obj2, ["dan", "stanhope"]);
//output: obj2 dan stanhope

//using old school
execute("dan", "stanhope");
//output: undefined "dan" "stanhope"

Ответ 14

Разница в том, что call() принимает аргументы функции отдельно, а apply() принимает аргументы функции в массиве.

Ответ 15

Мы можем дифференцировать методы вызова и применения, как показано ниже

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

APPLY: вызов функции с аргументом, представленным в виде массива. Вы можете использовать apply, если вы не знаете, сколько аргументов будет передано функции.

Существует преимущество использования приложения over call, нам не нужно изменять количество аргументов, мы можем изменить передаваемый массив.

В производительности нет большой разницы. Но мы можем сказать, что вызов бит быстрее, чем сравнение, потому что массив должен оцениваться в методе apply.

Ответ 16

Разница между этими методами заключается в том, как вы хотите передать параметры.

"A для массива и C для запятой" - это удобная мнемоника.

Ответ 17

Вызов и применение обоих используются для принудительного значения this при выполнении функции. Единственное отличие состоит в том, что call принимает аргументы n+1, где 1 - this и 'n' arguments. apply принимает только два аргумента, один - this, другой - массив аргументов.

Преимущество, которое я вижу в apply over call, состоит в том, что мы можем легко делегировать вызов функции другой функции без особых усилий;

function sayHello() {
  console.log(this, arguments);
}

function hello() {
  sayHello.apply(this, arguments);
}

var obj = {name: 'my name'}
hello.call(obj, 'some', 'arguments');

Обратите внимание, как легко делегировать hello в sayHello с помощью apply, но с call это очень трудно достичь.

Ответ 18

Даже если call и apply достигают того же, я думаю, что по крайней мере одно место, где вы не можете использовать call, но можете использовать только apply. Это то, когда вы хотите поддерживать наследование и хотите вызвать конструктор.

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

function makeClass( properties ) {
    var ctor = properties['constructor'] || function(){}
    var Super = properties['extends'];
    var Class = function () {
                 // Here 'call' cannot work, only 'apply' can!!!
                 if(Super)
                    Super.apply(this,arguments);  
                 ctor.apply(this,arguments);
                }
     if(Super){
        Class.prototype = Object.create( Super.prototype );
        Class.prototype.constructor = Class;
     }
     Object.keys(properties).forEach( function(prop) {
           if(prop!=='constructor' && prop!=='extends')
            Class.prototype[prop] = properties[prop];
     });
   return Class; 
}

//Usage
var Car = makeClass({
             constructor: function(name){
                         this.name=name;
                        },
             yourName: function() {
                     return this.name;
                   }
          });
//We have a Car class now
 var carInstance=new Car('Fiat');
carInstance.youName();// ReturnsFiat

var SuperCar = makeClass({
               constructor: function(ignore,power){
                     this.power=power;
                  },
               extends:Car,
               yourPower: function() {
                    return this.power;
                  }
              });
//We have a SuperCar class now, which is subclass of Car
var superCar=new SuperCar('BMW xy',2.6);
superCar.yourName();//Returns BMW xy
superCar.yourPower();// Returns 2.6

Ответ 19

Основное отличие заключается в том, что с помощью вызова мы можем изменить область и передать аргументы как обычно, но применять позволяет вам вызывать его, используя аргументы в качестве массива (передать их в виде массива). Но с точки зрения того, что они должны делать в вашем коде, они довольно похожи.

Хотя синтаксис этой функции практически идентичен синтаксису метода apply(), принципиальное отличие состоит в том, что call() принимает список аргументов, а apply() принимает один массив аргументов.

Итак, как видите, нет большой разницы, но все же есть случаи, когда мы предпочитаем использовать call() или apply(). Например, посмотрите на приведенный ниже код, который находит наименьшее и наибольшее число в массиве из MDN, используя метод apply:

// min/max number in an array
var numbers = [5, 6, 2, 3, 7];

// using Math.min/Math.max apply
var max = Math.max.apply(null, numbers); 
// This about equal to Math.max(numbers[0], ...)
// or Math.max(5, 6, ...)

var min = Math.min.apply(null, numbers)

Таким образом, главное отличие заключается в том, как мы передаем аргументы:

Вызов:

function.call(thisArg, arg1, arg2, ...);

Применять:

function.apply(thisArg, [argsArray]);

Ответ 20

Резюме:

Оба метода call() и apply() являются методами, которые находятся в Function.prototype. Поэтому они доступны для каждого объекта функции через цепочку прототипов. Обе функции call() и apply() могут выполнять функцию с указанным значением this.

Основное различие между call() и apply() заключается в способе передачи аргументов в него. В обоих call() и apply() вы передаете в качестве первого аргумента объект, который вы хотите быть значение, как this. Другие аргументы отличаются следующим образом:

  • С помощью call() вы должны вводить аргументы как обычно (начиная со второго аргумента)
  • С apply() вы должны передать массив аргументов.

Пример:

let obj = {
  val1: 5,
  val2: 10
}

const summation = function (val3, val4) {
  return  this.val1 + this.val2 + val3 + val4;
}

console.log(summation.apply(obj, [2 ,3]));
// first we assign we value of this in the first arg
// with apply we have to pass in an array


console.log(summation.call(obj, 2, 3));
// with call we can pass in each arg individually

Ответ 21

Позвольте мне добавить немного деталей к этому.

эти два вызова почти эквивалентны:

func.call(context, ...args); // pass an array as list with spread operator

func.apply(context, args);   // is same as using apply

Theres только небольшая разница:

  • Оператор spread... позволяет передавать итерируемый args в качестве списка для вызова.
  • apply принимает только массивоподобные аргументы.

Итак, эти звонки дополняют друг друга. Там, где мы ожидаем итеративность, работает call, а там, где мы ожидаем массива, - apply.

А для объектов, которые являются итеративными и похожими на массивы, например реальный массив, технически мы могли бы использовать любой из них, но apply, вероятно, будет быстрее, потому что большинство движков JavaScript его внутренне оптимизируют. лучше.

Ответ 22

  Разница между звонком и применением в Javascript

Одна очень распространенная вещь, которая сбивает меня с толку при написании Javascript - это знание, когда использовать call, а когда применять. Если вам интересно, что представляют собой эти методы, или вы не знаете, как работает область в JavaScript, то, возможно, имеет смысл сначала прочитать Руководство по Javascript.

Давайте рассмотрим, как мы можем их использовать:

var person1 = {name: 'awadh', age: 22, size: '6 xM'};
var person2 = {name: 'ravi', age: 22000000000, size: '3 xS'};

var sayHello = function(){
alert('Hey, ' + this.name); }; 

var sayGoodbye = function(){
alert('Thanks, ' + this.name); };

Теперь, если вы прочитали руководство, этот пример будет выглядеть действительно знакомым. Вы уже знаете, что пишете следующий код:

sayHello();
sayGoodbye();

выдаст ошибки (если вам повезет) или просто неожиданные результаты (если вы не). Это связано с тем, что обе функции полагаются на свою область видимости для данных this.name, и вызов их без явной области действия просто запустит их в области действия текущего окна.

Итак, как мы можем их охватить? Попробуйте это:

sayHello.call(person1);
sayGoodbye.call(person2);
sayHello.apply(person1);
sayGoodbye.apply(person2);

Все четыре из этих строк делают то же самое. Запустите sayHello или sayGoodbye в области person1 или person2.

И call, и apply выполняют очень похожие функции: они выполняют функцию в контексте или области действия первого передаваемого им аргумента. Кроме того, они обе функции, которые могут быть вызваны только для других функций. Вы не сможете запустить person1.call(), и в этом нет никакого смысла.

Разница в том, когда вы хотите заполнить этот вызов набором аргументов. Допустим, вы хотите сделать метод say() более динамичным:

var say = function(greeting){
alert(greeting + ', ' + this.name);  
  };
    say.call(person1, 'Hey'); say.call(person2, 'Thanks');

Так что звонок для тебя. Он запускает функцию в контексте первого аргумента, а последующие аргументы передаются в функцию для работы. Так как это работает с более чем одним аргументом?

    var update = function(name, age, size){
    this.name = name;
    this.age = age;
    this.size = size;
};

update.call(person1, 'chaurasia', 30, '4xM');

Ничего страшного. Они просто передаются в функцию, если она принимает более одного параметра.

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

    var dispatch = function(person, method, args){
    method.apply(person, args);
};

dispatch(person1, say, ['Hello']);
dispatch(person2, update, ['Slarty', 200, '1xM']);

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

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