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

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

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

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

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

вопрос задан 31.12.2009
John Duff
16426 репутация

20 ответов


  • 3342 рейтинг

    Разница в том, что 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
    ответ дан flatline, с репутацией 34582, 31.12.2009
  • 211 рейтинг

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

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

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

    Итак:

    // assuming you have f
    function f(message) { ... }
    f.call(receiver, "test");
    f.apply(receiver, ["test"]);
    
    ответ дан notnoop, с репутацией 49574, 31.12.2009
  • 151 рейтинг

    Чтобы ответить на часть о том, когда использовать каждую функцию, используйте 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, с репутацией 78981, 31.12.2009
  • 102 рейтинг

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

    ответ дан Joe, с репутацией 4375, 4.09.2013
  • 91 рейтинг

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

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


    [UPDATE!]

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

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

    .apply(this, [...])

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

    ответ дан kmatheny, с репутацией 3061, 7.11.2011
  • 72 рейтинг

    Далее следует выдержка из Закрытие: Полное руководство, автор Michael Bolin . Это может выглядеть немного длинным, но оно насыщено глубоким пониманием. Из «Приложения Б. Часто неверно понимаемые концепции 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, window - это глобальный объект, когда 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, с репутацией 3896, 4.12.2013
  • 33 рейтинг

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

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

    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, с репутацией 440, 25.02.2014
  • 23 рейтинг

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

    1. Bind возвращает экземпляр функции, которая может быть выполнена
    2. Первый параметр: «, это »,.
    3. Второй параметр - это список аргументов, разделенных запятыми, 99868408 (например, , вызов ).

    }

    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, с репутацией 1547, 31.03.2015
  • 21 рейтинг

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

    ответ дан does_not_exist, с репутацией , 5.07.2013
  • 20 рейтинг

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

    .call(scope, arg1, arg2, arg3)

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

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

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

    ответ дан Mark Karwowski, с репутацией 539, 21.01.2014
  • 18 рейтинг

    От Документы MDN о функции. прототип. apply () :

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

    Синтаксис

    fun.apply(thisArg, [argsArray])
    

    От Документы MDN о функции. прототип. call () :

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

    Синтаксис

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

    От Функция. применять и функционировать. позвоните в 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 += '

    output ' + position + '

    ' + JSON.stringify(obj) + '\n
    \n

    ';
    }
    
    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'
    ));

    См. Также this Fiddle .

    ответ дан John Slegers, с репутацией 26343, 18.01.2016
  • 11 рейтинг

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

    ответ дан Rakesh Kumar, с репутацией 2202, 28.02.2014
  • 10 рейтинг

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

    http: // sizeableidea. com / call-vs-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, с репутацией 988, 4.12.2013
  • 7 рейтинг

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

    ответ дан Sanjib Debnath, с репутацией 854, 11.08.2016
  • 6 рейтинг

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

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

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

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

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

    ответ дан Praveen D, с репутацией 1765, 6.11.2013
  • 5 рейтинг

    Вызов и применение обоих используются для принудительного вызова значения 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, с репутацией 3565, 24.11.2015
  • 5 рейтинг

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

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

    ответ дан venkat7668, с репутацией 1542, 3.08.2015
  • 4 рейтинг

    Хотя 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, с репутацией 1592, 12.02.2015
  • 3 рейтинг

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

    Хотя синтаксис этой функции практически идентичен синтаксису apply (), принципиальная разница в том, что call () принимает аргумент list, тогда как 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]);
    
    ответ дан Alireza, с репутацией 39782, 11.05.2017
  • 1 рейтинг

    Резюме:

    И 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, с репутацией 2793, 29.08.2018