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


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

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

func.apply();

против

func.call();

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


2709


источник


Ответы:


Разница в том, что applyпозволяет вам вызвать функцию с помощью argumentsкак массив; callтребует, чтобы параметры были перечислены явно. Полезная мнемоника " для лучей и С для с ОММА «.

См. Документацию 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


3282



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

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

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

Так:

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

205



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


151



Here's a good mnemonic. Apply uses Arrays and Always takes one or two Arguments. When you use Call you have to Count the number of arguments.


101



While this is an old topic, I just wanted to point out that .call is slightly faster than .apply. I can't tell you exactly why.

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


[UPDATE!]

Douglas Crockford mentions briefly the difference between the two, which may help explain the performance difference... http://youtu.be/ya4UHuXNygM?t=15m52s

Apply takes an array of arguments, while Call takes zero or more individual parameters! Ah hah!

.apply(this, [...])

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


91



Follows an extract from Closure: The Definitive Guide by Michael Bolin. It might look a bit lengthy, but it's saturated with a lot of insight. From "Appendix B. Frequently Misunderstood JavaScript Concepts":


What this Refers to When a Function is Called

When calling a function of the form foo.bar.baz(), the object foo.bar is referred to as the receiver. When the function is called, it is the receiver that is used as the value for 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);

If there is no explicit receiver when a function is called, then the global object becomes the receiver. As explained in "goog.global" on page 47, window is the global object when JavaScript is executed in a web browser. This leads to some surprising behavior:

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

Even though obj.addValues and f refer to the same function, they behave differently when called because the value of the receiver is different in each call. For this reason, when calling a function that refers to this, it is important to ensure that this will have the correct value when it is called. To be clear, if this were not referenced in the function body, then the behavior of f(20) and obj.addValues(20) would be the same.

Because functions are first-class objects in JavaScript, they can have their own methods. All functions have the methods call() and apply() which make it possible to redefine the receiver (i.e., the object that this refers to) when calling the function. The method signatures are as follows:

/**
* @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;

Note that the only difference between call() and apply() is that call() receives the function parameters as individual arguments, whereas apply() receives them as a single array:

// 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]);

The following calls are equivalent, as f and obj.addValues refer to the same function:

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

However, since neither call() nor apply() uses the value of its own receiver to substitute for the receiver argument when it is unspecified, the following will not work:

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

The value of this can never be null or undefined when a function is called. When null or undefined is supplied as the receiver to call() or apply(), the global object is used as the value for receiver instead. Therefore, the previous code has the same undesirable side effect of adding a property named value to the global object.

It may be helpful to think of a function as having no knowledge of the variable to which it is assigned. This helps reinforce the idea that the value of this will be bound when the function is called rather than when it is defined.


End of extract.


71



It is useful at times for one object to borrow the function of another object, meaning that the borrowing object simply executes the lent function as if it were its own.

A small code example:

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

These methods are very useful for giving objects temporary functionality.


33



Another example with Call, Apply and Bind. The difference between Call and Apply is evident, but Bind works like this:

  1. Bind returns an instance of a function that can be executed
  2. First Parameter is 'this'
  3. Second parameter is a Comma separated list of arguments (like 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
*/

23