javascript - unterschied - js call




Was ist der Unterschied zwischen Anruf und Bewerbung? (14)

Was ist der Unterschied zwischen call und apply , um eine Funktion aufzurufen?

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

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

Gibt es Leistungsunterschiede zwischen den beiden zuvor genannten Methoden? Wann ist es am besten, call over apply und umgekehrt?


Zusammenfassung:

Sowohl call() als auch apply() sind Methoden, die sich in Function.prototype . Sie sind daher für jedes Funktionsobjekt über die Prototypkette verfügbar. Sowohl call() als auch apply() können eine Funktion mit einem angegebenen Wert von this ausführen.

Der Hauptunterschied zwischen call() und apply() ist die Art und Weise, in die Sie Argumente übergeben müssen. In call() und apply() Sie als erstes Argument das Objekt, das Sie als Wert verwenden möchten. Die anderen Argumente unterscheiden sich in folgender Weise:

  • Mit call() Sie die Argumente normal eingeben (ab dem zweiten Argument)
  • Mit apply() Sie ein Array von Argumenten übergeben.

Beispiel:

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

Warum muss ich diese Funktionen verwenden?

this Wert kann in Javascript manchmal schwierig sein. Der Wert this Werts this bestimmt, wenn eine Funktion ausgeführt wird, nicht wenn eine Funktion definiert wird. Wenn unsere Funktion von einem Recht this Bindung abhängig ist, können wir call() und apply() , um dieses Verhalten durchzusetzen. Zum Beispiel:

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


Aus den MDN-Dokumenten zu Function.prototype.apply () :

Die apply () - Methode ruft eine Funktion mit einem gegebenen Wert und Argumenten auf, die als Array (oder Array-ähnliches Objekt) bereitgestellt werden.

Syntax

fun.apply(thisArg, [argsArray])

Aus den MDN-Dokumenten zu Function.prototype.call () :

Die call () -Methode ruft eine Funktion mit einem gegebenen Wert und einzelnen Argumenten auf.

Syntax

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

Von Function.apply und Function.call in JavaScript :

Die apply () -Methode ist identisch mit call (), mit der Ausnahme, dass apply () ein Array als zweiten Parameter erfordert. Das Array repräsentiert die Argumente für die Zielmethode.

Code-Beispiel:

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

Siehe auch diese Geige .


Call und Apply both werden verwendet, um this Wert zu erzwingen, wenn eine Funktion ausgeführt wird. Der einzige Unterschied besteht darin, dass der call n+1 Argumente akzeptiert, wobei 1 this und 'n' arguments . apply nimmt nur zwei Argumente an, eines ist das Argumentarray.

Der Vorteil, den ich in apply über call sehe apply ist, dass wir einen Funktionsaufruf ohne großen Aufwand leicht an andere Funktionen delegieren können.

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

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

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

Beobachten Sie, wie einfach wir hello an sayHello mit apply delegiert haben, aber mit call dies sehr schwer zu erreichen.


Der Hauptunterschied besteht darin, dass wir mithilfe von call den Gültigkeitsbereich ändern und Argumente wie gewohnt übergeben können. Mit apply können Sie ihn jedoch mit Argumenten als Array (als Array übergeben) aufrufen. Aber in Bezug auf das, was sie in Ihrem Code tun sollen, sind sie sich ziemlich ähnlich.

Während die Syntax dieser Funktion fast identisch mit der von apply () ist, besteht der grundlegende Unterschied darin, dass call () eine Argumentliste akzeptiert, während apply () ein einzelnes Array von Argumenten akzeptiert.

Wie Sie sehen, gibt es keinen großen Unterschied, aber es gibt Fälle, in denen wir call () oder apply () bevorzugen. Sehen Sie sich zum Beispiel den Code an, der die kleinste und größte Zahl in einem Array aus MDN ermittelt, und zwar mit der apply-Methode:

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

Der Hauptunterschied besteht also darin, wie wir die Argumente weitergeben:

Anruf:

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

Sich bewerben:

function.apply(thisArg, [argsArray]);

Der Unterschied besteht darin, dass Sie mit apply die Funktion mit arguments als Array aufrufen können. call erfordert, dass die Parameter explizit aufgelistet werden. Eine nützliche Erinnerung ist " A für einen Strahl und C für Komma".

Weitere Informationen finden Sie in der Dokumentation zu MDN.

Pseudosyntax:

theFunction.apply(valueForThis, arrayOfArgs)

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

Ab ES6 besteht auch die Möglichkeit, das Array zur Verwendung mit der call Funktion zu spread Die Kompatibilitäten können Sie here .

Beispielcode:

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


Der Unterschied zwischen diesen Methoden besteht darin, wie Sie die Parameter übergeben möchten.

"A für Array und C für Komma" ist eine praktische Erinnerung.


Folgt einen Auszug aus Closure: The Definitive Guide von Michael Bolin . Es sieht zwar etwas langwierig aus, ist aber mit viel Einsicht gefüllt. In "Anhang B. Häufig missverstandene JavaScript-Konzepte":

Worauf sich this bezieht, wenn eine Funktion aufgerufen wird

Beim Aufruf einer Funktion der Form foo.bar.baz() wird das Objekt foo.bar als Empfänger bezeichnet. Beim Aufruf der Funktion wird der Empfänger als Wert 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);

Wenn beim Aufruf einer Funktion kein expliziter Empfänger vorhanden ist, wird das globale Objekt zum Empfänger. Wie in "goog.global" auf Seite 49 erläutert, ist window das globale Objekt, wenn JavaScript in einem Webbrowser ausgeführt wird. Dies führt zu überraschendem Verhalten:

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

Obwohl sich obj.addValues und f auf dieselbe Funktion beziehen, verhalten sie sich beim Aufruf anders, da der Wert des Empfängers bei jedem Aufruf unterschiedlich ist. Aus diesem Grund muss beim Aufruf einer Funktion, die darauf verweist, sichergestellt sein, dass this beim Aufruf den richtigen Wert hat. Wenn this im Funktionskörper nicht angegeben ist, wäre das Verhalten von f(20) und obj.addValues(20) dasselbe.

Da Funktionen in JavaScript erstklassige Objekte sind, können sie ihre eigenen Methoden haben. Alle Funktionen haben die Methoden call() und apply() , die es ermöglichen, den Empfänger (dh das Objekt, auf das sich this Objekt bezieht) beim Aufruf der Funktion neu zu definieren. Die Methodensignaturen lauten wie folgt:

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

Beachten Sie, dass der einzige Unterschied zwischen call() und apply() besteht, dass call() die Funktionsparameter als einzelne Argumente empfängt, während apply() sie als einzelnes Array empfängt:

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

Die folgenden Aufrufe sind gleichwertig, da sich f und obj.addValues auf dieselbe Funktion beziehen:

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

Da jedoch weder call() noch apply() den Wert seines eigenen Empfängers verwenden, um das Empfängerargument zu ersetzen, wenn es nicht angegeben ist, funktioniert Folgendes nicht:

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

Der Wert this Wertes kann beim Aufruf einer Funktion niemals null oder undefined . Wenn null den call() von call() oder apply() null oder undefined wird, wird stattdessen das globale Objekt als Wert für den Empfänger verwendet. Daher hat der vorherige Code den gleichen unerwünschten Nebeneffekt, wenn er dem globalen Objekt eine Eigenschaft namens value hinzufügt.

Es kann hilfreich sein, an eine Funktion zu denken, die keine Kenntnis über die Variable hat, der sie zugeordnet ist. Dies hilft, die Vorstellung zu verstärken, dass der Wert davon beim Aufruf der Funktion und nicht beim Definieren begrenzt wird.

Ende des Auszuges


Grundlegender Unterschied ist, dass call() eine Argumentliste akzeptiert, während apply() ein einzelnes Array von Argumenten akzeptiert.


Hier ist eine gute Erinnerung. A pply verwendet A- Strahlen und A lways immer ein oder zwei Argumente. Wenn Sie C verwenden , müssen Sie die Anzahl der Argumente angeben.


Ich möchte ein Beispiel zeigen, wo das Argument 'valueForThis' verwendet wird:

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] 

** Details: http://es5.github.io/#x15.4.4.7 *


Manchmal ist es nützlich, dass ein Objekt die Funktion eines anderen Objekts entlehnt, was bedeutet, dass das entliehene Objekt die ausgeliehene Funktion einfach so ausführt, als wäre es seine eigene.

Ein kleines Codebeispiel:

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

Diese Methoden sind sehr nützlich, um Objekten temporäre Funktionalität zu geben.


Obwohl call und apply das gleiche bewirken, glaube ich, dass es zumindest einen Ort gibt, an dem Sie call nicht verwenden können call sondern nur apply . Dann möchten Sie die Vererbung unterstützen und den Konstruktor aufrufen.

Mit dieser Funktion können Sie Klassen erstellen, die auch das Erstellen von Klassen unterstützen, indem Sie andere Klassen erweitern.

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

Um den Teil über die Verwendung der einzelnen Funktionen zu beantworten, verwenden Sie apply wenn Sie die Anzahl der übergebenen Argumente nicht kennen oder wenn sie sich bereits in einem Array oder einem Array-ähnlichen Objekt befinden (wie das Objekt arguments , um Ihre eigenen weiterzuleiten Argumente: Verwenden Sie den call andernfalls, da die Argumente nicht in ein Array eingeschlossen werden müssen.

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

Wenn ich keine Argumente weitergebe (wie in Ihrem Beispiel), ziehe ich einen call da ich die Funktion aufrufe. apply würde bedeuten, dass Sie die Funktion auf die (nicht vorhandenen) Argumente anwenden .

Es sollte keine Leistungsunterschiede geben, außer wenn Sie die Argumente in einem Array apply und f.apply(thisObject, [a, b, c]) (z. B. f.apply(thisObject, [a, b, c]) anstelle von f.call(thisObject, a, b, c) ). Ich habe es nicht getestet, daher könnte es Unterschiede geben, aber es wäre sehr browserspezifisch. Es ist wahrscheinlich, dass der call schneller ist, wenn Sie die Argumente nicht bereits in einem Array haben, und die apply dann schneller ist.


Wir können die Anruf- und Methoden wie folgt unterscheiden

CALL: Eine Funktion mit Argumente einzeln stellen. Wenn Sie die zu übergebenden Argumente kennen oder es kein zu übergebendes Argument gibt, können Sie call verwenden.

APPLY: Rufen Sie eine Funktion mit einem als Array angegebenen Argument auf. Sie können apply anwenden, wenn Sie nicht wissen, wie viele Argumente an die Funktion übergeben werden.

Es gibt einen Vorteil der Anwendung von "Anwendung über Aufruf". Wir müssen nicht die Anzahl der Argumente ändern, sondern nur ein Array, das übergeben wird.

Es gibt keinen großen Leistungsunterschied. Wir können jedoch sagen, dass der Aufruf als Vergleich etwas schneller ist, da ein Array in der Anwendungsmethode ausgewertet werden muss.





dynamic