В чем разница между call и apply?

avatar
John Duff
31 декабря 2009 в 19:56
748299
26
3255

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

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

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

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

Источник
Larry Battle
12 июня 2012 в 06:17
744

Подумайте о a в приложении для массива аргументов и c в вызове столбцов аргументов.

Samih
6 декабря 2013 в 16:20
189

@LarryBattle Я делаю почти то же самое, но думаю, что a in применяется для массива и c в вызове для запятой (т.е. аргументы, разделенные запятыми).

Ringo
10 марта 2014 в 22:55
7

Согласен, это глупо. Что раздражает, так это то, что этот вопрос почему-то задают во время собеседований, потому что какой-то влиятельный болван добавил его в свой список важных js-вопросов.

neaumusic
26 ноября 2014 в 10:53
0

массив «arguments» по умолчанию, который передается в область видимости функции, передается с помощью apply. аргументы идут с массивом идет с применением, call принимает ручной список моделей, а не объект коллекции (массив)

Gras Double
4 декабря 2014 в 03:27
11

Вы подаете заявку на вакансию один раз (один аргумент), вы [телефон] звоните людям много раз (несколько аргументов). Альтернатива: есть [тоже?] Много Call игр Duty.

Gras Double
4 декабря 2014 в 03:33
0

Более классический, есть только один массив, вы применяете его [в целом], есть несколько аргументов, вы вызываете их [подряд]. Сделайте ваш выбор :)

Gajus
18 декабря 2014 в 01:22
1

Когда намерение состоит в том, чтобы вызвать вариативную функцию со списком значений аргументов независимо от значения «this», тогда используйте оператор распространения ES6, например fn(...input), где ввод - это массив. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

DevWL
23 марта 2016 в 17:51
1

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

Ankit Singh
14 декабря 2016 в 07:57
1

В ES6, если у вас есть массив аргументов args, разница будет только в три точки .... то есть: fn.apply(context, args) или fn.call(context, ...args)

Ответы (26)

avatar
flatline
31 декабря 2009 в 20:00
3796

Разница в том, что apply позволяет вызывать функцию с arguments в виде массива; call требует, чтобы параметры были указаны явно. Полезная мнемоника: " A для a rray и C для c <6om396901187> c<6om396901189>

См. Документацию MDN по применить и позвонить по.

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

theFunction.apply(valueForThis, arrayOfArgs)

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

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

Пример кода:

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

devios1
23 июня 2011 в 01:31
0

Оба ли они поддерживаются большинством браузеров? Кажется, я помню, как читал, что call() больше относился к IE.

Kevin Schroeder
28 июля 2012 в 16:18
28

Следует добавить, что аргументы должны быть числовым массивом ([]). Ассоциативные массивы ({}) работать не будут.

Martijn
10 января 2013 в 15:19
353

@KevinSchroeder: На языке javascript [] называется массивом , {} называется объектом .

aziz punjani
6 октября 2013 в 20:43
95

Я часто забывал, что принимает массив, а что ожидает от вас перечисления аргументов. Техника, которую я использовал, чтобы запомнить, заключается в том, что если первая буква метода начинается с a , тогда он принимает массив, то есть a массив pply

some
16 июля 2014 в 05:04
19

@SAM Использование вызова вместо обычного вызова функции имеет смысл только в том случае, если вам нужно изменить значение this для вызова функции. Пример (который преобразует объект-аргумент функции в массив): Array.prototype.slice.call(arguments) или [].slice.call(arguments). apply имеет смысл, если у вас есть аргументы в массиве, например, в функции, которая вызывает другую функцию с (почти) теми же параметрами. Рекомендация Используйте обычный вызов функции funcname(arg1), если это дает то, что вам нужно, и сохраните вызов и примените для тех особых случаев, когда они вам действительно нужны.

Ralph Cowling
10 ноября 2014 в 11:33
1

theFunction.call(undefined, ["Claude", "mathematician"]); // 'My name is Claude,mathematician and I am a undefined.' О, Клод! <3 (photos-5.dropbox.com/t/1/…)

Kunal Singh
27 августа 2015 в 06:40
1

theFunction.apply (undefined, [«Сьюзен», «школьный учитель»]); theFunction.call (undefined, «Клод», «математик»); Почему при вызове первый аргумент не определен?

A J Qarshi
24 февраля 2016 в 12:42
6

@KunalSingh Оба параметра call и apply принимают два параметра. Первым аргументом функции apply' and call` должен быть объект-владелец, а вторым параметром будет массив или параметры, разделенные запятыми соответственно. Если вы передадите null или undefined в качестве первого аргумента, тогда в нестрогом режиме они будут заменены глобальным объектом, то есть window

xgqfrms
25 декабря 2016 в 12:07
0

# коды ошибок theFunction.apply(undefined, ...["Matthew", "physicist"]); A_better_apply

Álvaro González
24 мая 2017 в 09:05
3

Сама по себе мнемоника заслуживает ответа. Не думаю, что мне нужно снова искать его!

candy_man
5 января 2018 в 10:26
2

@AJQarshi @KunalSingh Чтобы объяснить ответ Карши, первый аргумент, объект-владелец, как он его назвал, - это контекст выполнения, который вы хотите передать функции (this контекст). Когда объект передается в качестве аргумента, вызываемая функция привязывается к контексту выполнения объекта, и любая ссылка на члены в функции действительно будет указывать на существующие члены объекта. Надеюсь, это имеет смысл.

Brain2000
17 июля 2019 в 15:08
0

Итак, что касается прокси-сервера JavaScript и оператора распространения, будет ли Handler.Call (target, that, ... args) таким же, как Handler.Apply (target, that, args)?

Jakub Kubista
3 июня 2020 в 18:09
0

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

avatar
Ran Turner
24 декабря 2021 в 18:26
0

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

object.someMethod.call( someObject, arguments )

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

object.someMethod.apply( someObject, arrayOfarguments )

var car  = {  
  name: "Reno",
  country: "France",
  showBuyer: function(firstName, lastName) {
    console.log(`${firstName} ${lastName} just bought a ${this.name} from ${this.country}`);
  }
}

const firstName = "Bryan";
const lastName = "Smith";

car.showBuyer(firstName, lastName);  // Bryan just bought a Reno from France

const obj = { name: "Maserati", country: "Italy" };

car.showBuyer.call(obj, firstName, lastName); // Bryan Smith just bought a Maserati from Italy

car.showBuyer.apply(obj, [firstName, lastName]); // Bryan Smith just bought a Maserati from Italy
avatar
bisma
26 декабря 2020 в 14:52
1

позвонить () Это предопределенный метод в javascript. Этот метод вызывает метод (функцию) путем указания объекта-владельца.

  function sayHello(){
  return "Hello " + this.name;
}
        
var obj = {name: "Sandy"};
        
sayHello.call(obj);
        
// Returns "Hello Sandy"

Вызов принимает аргумент

function saySomething(message){
  return this.name + " is " + message;
}
        
var person4 = {name:  "John"};
        
saySomething.call(person4, "awesome");
// Returns "John is awesome"    

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

пример

function saySomething(message){
  return this.name + " is " + message;
}
        
var person4 = {name:  "John"};
        
saySomething.apply(person4, ["awesome"]);
avatar
Leela Narasimha
2 августа 2020 в 05:25
0

И вызывают, и применяют одинаково. Он вызывается немедленно, когда мы используем call and apply.

И call, и apply принимают параметр this в качестве первого аргумента, а отличается только второй аргумент.

вызов принимает аргументы функций в виде списка (запятая) Apply принимает аргументы функций в виде массива.

Вы можете найти полную разницу между привязкой, вызовом и применением в видео ниже на YouTube.

https://www.youtube.com/watch?v=G-EfxnG0DtY&t=180s

avatar
unsuredev
25 июня 2020 в 17:11
-2

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

apply() - Подобно методу call(), первый параметр в методе apply() устанавливает значение this, которое является объектом, для которого вызывается функция. В данном случае это объект obj выше. Единственная разница между методами apply() и call() заключается в том, что второй параметр метода apply() принимает аргументы фактической функции в виде массива. enter image description here

Vega
25 июня 2020 в 17:57
3

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

avatar
Abdul Rehman Kaim Khani
11 июня 2020 в 08:42
0

Хорошо объяснено плоской линией. Я просто хочу добавить простой пример. что упрощает понимание для новичков.

func.call(context, args1 , args2 ); // pass arguments as "," saprated value

func.apply(context, [args1 , args2 ]);   //  pass arguments as "Array"

мы также используем методы «Call» и «Apply» для изменения ссылки , как определено в коде ниже

    let Emp1 = {
        name: 'X',
        getEmpDetail: function (age, department) {
            console.log('Name :', this.name, '  Age :', age, '  Department :', department)
        }
    }
    Emp1.getEmpDetail(23, 'Delivery')

    // 1st approch of chenging "this"
    let Emp2 = {
        name: 'Y',
        getEmpDetail: Emp1.getEmpDetail
    }
    Emp2.getEmpDetail(55, 'Finance')

    // 2nd approch of changing "this" using "Call" and "Apply"
    let Emp3 = {
        name: 'Z',
    }

    Emp1.getEmpDetail.call(Emp3, 30, 'Admin')        
// here we have change the ref from **Emp1 to Emp3**  object
// now this will print "Name =  X" because it is pointing to Emp3 object
    Emp1.getEmpDetail.apply(Emp3, [30, 'Admin']) //
avatar
Pravin Divraniya
12 сентября 2019 в 07:38
2

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

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

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

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

Есть лишь небольшая разница:

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

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

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

avatar
Willem van der Veen
29 августа 2018 в 15:29
4

Сводка:

И 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
avatar
Alireza
11 мая 2017 в 14:35
4

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

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

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

// 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]);
avatar
Sanjib Debnath
11 августа 2016 в 09:25
8

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

avatar
John Slegers
18 января 2016 в 02:27
19

Из документы 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'
));

См. Также этот Fiddle .

avatar
Raghavendra
24 ноября 2015 в 08:36
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 этого очень трудно достичь.

avatar
venkat7668
3 августа 2015 в 06:15
5

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

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

Kyll
7 сентября 2015 в 10:38
12

Что дает этот ответ, чего еще не было в других ответах?

avatar
Mahesh
31 марта 2015 в 07:32
26

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

  1. Bind возвращает экземпляр функции, которая может быть выполнена
  2. Первый параметр - ' это '
  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
*/
avatar
Dhana Krishnasamy
12 февраля 2015 в 18:10
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
jhliberty
25 октября 2017 в 19:10
0

Я считаю, что звонок будет работать там с оператором спреда, как описано в выбранном ответе. Если я чего-то не упускаю.

avatar
Rakesh Kumar
28 февраля 2014 в 04:57
12

Фундаментальное отличие состоит в том, что call() принимает список аргументов , а apply() принимает <46775468373280> одиночный массив аргументов.

Faraz Kelhini
13 марта 2014 в 18:52
1

источник: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

avatar
tjacks3
25 февраля 2014 в 19:31
36

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

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

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

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

Michel Ayres
25 февраля 2014 в 19:50
1

Людям, которые хотят знать, как увидеть console.log, проверьте: Что такое console.log и как его использовать?

avatar
Mark Karwowski
21 января 2014 в 18:11
21

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

.call(scope, arg1, arg2, arg3)

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

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

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

xgqfrms
25 декабря 2016 в 13:52
0

`// call () === аргументы, разделенные запятыми (список-аргументов) .call (this, args1, args2, args3, ...) // apply () === массив аргументов (элементы-массивы). apply (this, [arr0, arr1, arr2, ...]) `

avatar
Dan
4 декабря 2013 в 13:58
10

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

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"
Mark Karwowski
21 января 2014 в 18:07
0

вот еще один: blog.i-evaluation.com/2012/08/15/javascript-call-and-apply, но в основном это правильно: .call (scope, arg1, arg2, arg3)

avatar
Dominykas Mostauskis
4 декабря 2013 в 12:41
78

Следует отрывок из Closure: The Definitive Guide Майкла Болина. Это может показаться немного длинным, но оно насыщено глубоким пониманием. Из «Приложения Б. Часто неправильно понимаемые концепции 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 к глобальному объекту.

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


Конец отрывка.

Viktor Stolbin
27 октября 2015 в 12:12
0

Просто обратите внимание на тот факт, что additionalValues не упоминается внутри obj.addValues тела

jhliberty
25 октября 2017 в 19:15
0

Я знаю, что вы отвечали на вопрос, но хотели бы добавить: вы могли использовать bind при определении f. var f = obj.addValues; становится var f = obj.addValues.bind(obj), и теперь f (20) будет работать без необходимости каждый раз использовать call или применять.

Fralcon
7 февраля 2020 в 01:14
0

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

avatar
Praveen D
6 ноября 2013 в 11:50
6

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

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

ПРИМЕНИТЬ: вызвать функцию с аргументом, предоставленным в виде массива. Вы можете использовать apply, если не знаете, сколько аргументов будет передано функции.

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

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

avatar
Joe
4 сентября 2013 в 13:36
118

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

dantheta
3 ноября 2013 в 11:40
2

Полезная мнемоника тут же !. Я заменю «один или два аргумента» на «максимум два аргумента», поскольку ни первый, ни второй параметры apply не требуются. Я не уверен, почему можно вызывать apply или call без параметра. Похоже, кто-то пытается выяснить, почему здесь coderhelper.com/questions/15903782/…

avatar
user669677
5 июля 2013 в 10:56
23

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

avatar
kmatheny
7 ноября 2011 в 17:36
95

Хотя это старая тема, я просто хотел отметить, что .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...)

Eric Hodonsky
1 марта 2012 в 20:30
0

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

Josh Mc
11 мая 2012 в 01:42
12

Что интересно, даже без массива вызов по-прежнему выполняется намного быстрее. jsperf.com/applyvscallvsfn2

Vincent McNabb
8 октября 2013 в 01:10
0

@JoshMc Это было бы очень специфично для браузера. В IE 11 подача заявки выполняется вдвое быстрее, чем вызов.

joeytwiddle
23 ноября 2013 в 16:41
1

1. Создание нового массива означает, что сборщику мусора в какой-то момент потребуется его очистить. 2. Доступ к элементам в массиве с помощью разыменования менее эффективен, чем прямой доступ к переменной (параметру). (Я полагаю, что именно это имел в виду kmatheny под «синтаксическим анализом», что на самом деле представляет собой нечто совершенно иное.) Но ни один из моих аргументов не объясняет jsperf. Это должно быть связано с реализацией двух функций движком, например возможно, они все равно создают пустой массив, если ничего не было передано.

Gary
23 июля 2017 в 11:22
0

Спасибо, что поделились тестом и видео

avatar
Matthew Crumley
31 декабря 2009 в 21:50
168

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

avatar
notnoop
31 декабря 2009 в 19:59
244

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

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

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

Итак:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
angry kiwi
29 июля 2011 в 04:01
46

второй параметр apply () и call () является необязательным, необязательным.

Ikrom
5 июня 2013 в 05:33
37

Первый параметр тоже не требуется.

iamcastelli
28 января 2020 в 06:58
2

@Ikrom, первый параметр не требуется для call, но требуется для apply