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

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

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

func.apply(); против func.call();

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

2826 голосов | спросил John Duff 31 ThuEurope/Moscow2009-12-31T22:56:25+03:00Europe/Moscow12bEurope/MoscowThu, 31 Dec 2009 22:56:25 +0300 2009, 22:56:25

19 ответов


0

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

См. документацию MDN по apply и call .

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

theFunction.apply(valueForThis, arrayOfArgs)

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

Начиная с ES6, существует также возможность ---- +: = 5 =: + ---- массив для использования с spread

Пример кода:

 call
ответил flatline 31 ThuEurope/Moscow2009-12-31T23:00:42+03:00Europe/Moscow12bEurope/MoscowThu, 31 Dec 2009 23:00:42 +0300 2009, 23:00:42
0

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

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

  

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

Итак:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
ответил notnoop 31 ThuEurope/Moscow2009-12-31T22:59:36+03:00Europe/Moscow12bEurope/MoscowThu, 31 Dec 2009 22:59:36 +0300 2009, 22:59:36
0

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

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

f.apply(thisObject, arguments); // Forward this function's 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 быстрее, если вы это сделаете.

ответил Matthew Crumley 1 Jam1000000amFri, 01 Jan 2010 00:50:40 +030010 2010, 00:50:40
0

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

ответил Joe 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowWed, 04 Sep 2013 17:36:59 +0400 2013, 17:36:59
0

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

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


[UPDATE!]

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

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

.apply(this, [...])

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

ответил kmatheny 7 12011vEurope/Moscow11bEurope/MoscowMon, 07 Nov 2011 21:36:45 +0400 2011, 21:36:45
0

Далее следует выдержка из Закрытие: полное руководство Майкла Болина . Это может выглядеть немного длинным, но оно насыщено глубоким пониманием. Из «Приложения Б. Часто неверно понимаемые концепции 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 при вызове функции. Когда null или undefined предоставляется как получатель для call() или apply(), глобального объект используется вместо значения для получателя. Поэтому предыдущий код имеет тот же нежелательный побочный эффект, что и добавление свойства с именем value к глобальному объекту.

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


Конец извлечения.

ответил Dominykas Mostauskis 4 WedEurope/Moscow2013-12-04T16:41:08+04:00Europe/Moscow12bEurope/MoscowWed, 04 Dec 2013 16:41:08 +0400 2013, 16:41:08
0

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

Небольшой пример кода:

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

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

ответил tjacks3 25 FebruaryEurope/MoscowbTue, 25 Feb 2014 23:31:51 +0400000000pmTue, 25 Feb 2014 23:31:51 +040014 2014, 23:31:51
0

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

  1. Bind возвращает экземпляр функции, которая может быть выполнена
  2. Первый параметр - это this '
  3. Второй параметр - это разделенный запятыми список аргументов (например, 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
*/
ответил Mahesh 31 MaramTue, 31 Mar 2015 10:32:05 +03002015-03-31T10:32:05+03:0010 2015, 10:32:05
0

Я хотел бы показать пример, где используется аргумент '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 *

ответил 5 J000000Friday13 2013, 14:56:04
0

Call () принимает аргументы через запятую, например:

.call(scope, arg1, arg2, arg3)

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

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

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

ответил Mark Karwowski 21 Jpm1000000pmTue, 21 Jan 2014 22:11:22 +040014 2014, 22:11:22
0

Из документов 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 () идентичен call (), за исключением того, что 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'
));

См. также эту скрипку .

ответил John Slegers 18 Jam1000000amMon, 18 Jan 2016 05:27:00 +030016 2016, 05:27:00
0

Принципиальное отличие заключается в том, что call() принимает список аргументов , а ---- +: = 1 =: + ---- принимает один массив аргументов .

ответил Rakesh Kumar 28 FebruaryEurope/MoscowbFri, 28 Feb 2014 08:57:48 +0400000000amFri, 28 Feb 2014 08:57:48 +040014 2014, 08:57:48
0

Вот небольшой пост, о котором я писал:

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"
ответил Dan 4 WedEurope/Moscow2013-12-04T17:58:29+04:00Europe/Moscow12bEurope/MoscowWed, 04 Dec 2013 17:58:29 +0400 2013, 17:58:29
0

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

ответил Sanjib Debnath 11 PM000000120000002331 2016, 12:25:23
0

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

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

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

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

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

ответил Praveen D 6 32013vEurope/Moscow11bEurope/MoscowWed, 06 Nov 2013 15:50:46 +0400 2013, 15:50:46
0

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

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

ответил venkat7668 3 AM00000090000001631 2015, 09:15:16
0

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

Преимущество, которое я вижу в apply перед 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 Этого очень трудно достичь.

ответил Raghavendra 24 22015vEurope/Moscow11bEurope/MoscowTue, 24 Nov 2015 11:36:02 +0300 2015, 11:36:02
0

Несмотря на то, что 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
ответил Dhana Krishnasamy 12 FebruaryEurope/MoscowbThu, 12 Feb 2015 21:10:05 +0300000000pmThu, 12 Feb 2015 21:10:05 +030015 2015, 21:10:05
0

Резюме:

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

Зачем мне использовать эти функции?

Значение this может быть сложным, иногда в javascript. Значение this определяется при выполнении функции, а не при определении функции. Если наша функция зависимая справа this мы можем использовать call() и apply(), чтобы применить это поведение. Например:

 var name = 'unwantedGlobalName';

const obj =  {
  name: 'Willem',
  sayName () { console.log(this.name);}
}


let copiedMethod = obj.sayName;
// we store the function in the copiedmethod variable



copiedMethod();
// this is now window, unwantedGlobalName gets logged

copiedMethod.call(obj);
// we enforce this to be obj, Willem gets logged
ответил Willem van der Veen 29 PM00000060000004231 2018, 18:29:42

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132