Kontext verwenden Anruf und in Javascript anwenden?

74

Leute, kann jemand den zu verwendenden Kontext callund die applyMethoden in Javascript erklären ?

Warum eine Funktion verwenden callund applynicht direkt aufrufen?

Kirsche
quelle
3
Diese Lektüre hat mir geholfen zu verstehen, thisArgwann ich anrufe apply()und call()was der Kern Ihrer Frage zu sein scheint. Sie müssen Funktionsaufrufprimitiv in Javascript
Saba Ahang

Antworten:

80

Sie verwenden calloder applywenn Sie einen anderen thisWert an die Funktion übergeben möchten . Im Wesentlichen bedeutet dies, dass Sie eine Funktion so ausführen möchten, als wäre sie eine Methode eines bestimmten Objekts. Der einzige Unterschied zwischen den beiden besteht darin, calldass durch Kommas getrennte Parameter erwartet werden, während applyParameter in einem Array erwartet werden.

Ein Beispiel von Mozillas applySeite , auf der Konstruktoren verkettet sind:

function Product(name, price) {
    this.name = name;
    this.price = price;

    if (price < 0)
        throw RangeError('Cannot create product "' + name + '" with a negative price');
    return this;
}

function Food(name, price) {
    Product.apply(this, arguments);
    this.category = 'food';
}
Food.prototype = new Product();

function Toy(name, price) {
    Product.apply(this, arguments);
    this.category = 'toy';
}
Toy.prototype = new Product();

var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);

Was Product.apply(this, arguments)tut , ist Folgendes: Der ProductKonstruktor wird als Funktion in jedem von der Anwendung Foodund ToyKonstrukteuren, und jede dieser Objektinstanzen werden als bestanden this. Somit hat jeder von Foodund Toyjetzt this.nameund this.categoryEigenschaften.

Kevinji
quelle
6
Nur eine Frage zum bereitgestellten Code-Snippet: Warum wird der Prototyp von Toy and Food durch ein Produktobjekt ersetzt?
David
Nur um @davids Frage zu beantworten: Warum müssen wir das tun Toy.prototype = new Product();? Ich habe dies getestet und das Entfernen dieser Zeilen scheint keinen Unterschied im Endergebnis zu machen.
Adrianp
6
@davids & @adrianp: Es wird benötigt, damit Lebensmittel und Spielzeug vom Produkt erben. Schauen Sie sich dieses Beispiel an: jsfiddle.net/Shawn/xNEYf Ich habe es entfernt, Toy.prototype = new Product();aber belassen Food.prototype = new Product();, also erbt Food jetzt von Product, Toy jedoch nicht. Ich habe dem Produktprototyp auch eine Methode hinzugefügt und sie von Food and Toy aufgerufen, um die fehlende Vererbung deutlicher zu machen (öffnen Sie einfach die Konsole und führen Sie den Code aus. Food kann die von Product geerbte Methode aufrufen, Toy kann jedoch keinen Fehler auslösen). .
Shawn
Wie würde der Prototyp verwendet, wenn er mit Objektliteralen verwendet wird?
user244394
Ich glaube, ich verstehe den Zweck dafür einfach nicht, anstatt etwas, das viel einfacher zu sein scheint, wie dieses .
22

Nur wenn Sie den Kontext innerhalb der Funktion verwenden calloder applyändern thiskönnen.

Im Gegensatz zu anderen Sprachen thisbezieht sich JavaScript nicht auf das aktuelle Objekt, sondern auf den Ausführungskontext und kann vom Aufrufer festgelegt werden.

Wenn Sie eine Funktion mit dem newSchlüsselwort aufrufen this, verweist sie korrekt auf das neue Objekt (innerhalb der Konstruktorfunktion).

In allen anderen Fällen thisbezieht sich - auf das globale Objekt, sofern es nicht explizit durch Aufruf festgelegt wird

Migräne
quelle
Bei Verwendung der obj.whatever();Syntax kann es sich auf den Aufrufer obj beziehen .
Abhishek Soni
Die Aussage "Aber in allen anderen Fällen - dies bezieht sich auf das globale Objekt, sofern es nicht explizit durch Aufruf festgelegt wurde" sollte wie folgt korrigiert werden: "In allen anderen Fällen bezieht sich dies, sofern es nicht explizit durch Aufruf festgelegt wird, auf das globale Objekt, wenn es verwendet wird Ecmascript 3 oder Ecmascript 5 (oder höher) im nicht strengen Modus. In Ecmascript 5 (oder höher) im strengen Modus ist dies jedoch immer undefiniert, wenn es nicht explizit festgelegt ist, und die JS Engine löst eine Ausnahme aus, wenn Sie darauf zugreifen. " Siehe: stackoverflow.com/questions/9822561/…
Alan CS
10

Sie verwenden diese Option, .call()wenn eine Funktion mit einem anderen thisWert ausgeführt werden soll. Es setzt den thisWert wie angegeben, setzt die Argumente wie angegeben und ruft dann die Funktion auf. Der Unterschied zwischen .call()und nur das Ausführen der Funktion ist der Wert des thisZeigers, wenn die Funktion ausgeführt wird. Wenn Sie die Funktion normal ausführen, entscheidet Javascript über den thisZeiger (normalerweise der globale Kontext, windowsofern die Funktion nicht als Methode für ein Objekt aufgerufen wird). Wenn Sie verwenden .call(), geben Sie genau an, auf was Sie eingestellt werden möchten this.

Sie werden verwendet, .apply()wenn sich die Argumente, die Sie an eine Funktion übergeben möchten, in einem Array befinden. .apply()kann auch dazu führen, dass eine Funktion mit einem bestimmten thisWert ausgeführt wird. .apply()wird am häufigsten verwendet, wenn Sie eine unbestimmte Anzahl von Argumenten haben, die aus einer anderen Quelle stammen. Es wird häufig auch verwendet, um die Argumente von einem Funktionsaufruf an einen anderen zu übergeben, indem die spezielle lokale Variable verwendet wird, argumentsdie ein Array von Argumenten enthält, die an Ihre aktuelle Funktion übergeben wurden.

Ich finde die MDN-Referenzseiten für .call () und .apply () hilfreich.

jfriend00
quelle
Danke, du erklärst es sehr gut. Schließlich verstehen Sie die Verwendung des ersten Arguments.
Frage Überlauf
4

Wenn Sie Erfahrung mit jQuery haben, wissen Sie, dass die meisten Funktionen das thisObjekt verwenden. Zum Beispiel collection.each(function() { ... }); Innerhalb dieser Funktion "this"bezieht sich auf das Iterator - Objekt. Dies ist eine mögliche Verwendung.

Ich persönlich habe .apply()für die Implementierung einer Warteschlange von Anforderungen verwendet - ich schiebe ein Array von Argumenten in die Warteschlange, und wenn die Zeit für die Ausführung gekommen ist, nehme ich ein Element und übergebe es als Argumente für eine Handlerfunktion mit .apply(), wodurch die Code Cleaner dann, wenn ein Array von Argumenten als erstes Argument übergeben werden muss. Das ist ein weiteres Beispiel.

Denken Sie im Allgemeinen daran, dass diese Möglichkeiten zum Aufrufen einer Funktion vorhanden sind und dass Sie sie eines Tages möglicherweise für die Implementierung Ihres Programms verwenden können.

Ivo
quelle
1

Wenn Sie Erfahrung mit dem Object Oriented ProgrammingAufrufen und Anwenden haben, ist es sinnvoll, wenn Sie es mit der Vererbung vergleichen und die Eigenschaften oder Methoden / Funktionen der übergeordneten Klasse von der untergeordneten Klasse überschreiben. Welches ist ähnlich mit Aufruf in Javascript wie folgt:

function foo () {
  this.helloworld = "hello from foo"
}
foo.prototype.print = function () {
  console.log(this.helloworld)
}

foo.prototype.main = function () {
  this.print()
}


function bar() {
  this.helloworld = 'hello from bar'
}
// declaring print function to override the previous print
bar.prototype.print = function () {
  console.log(this.helloworld)
}

var iamfoo = new foo()

iamfoo.main() // prints: hello from foo

iamfoo.main.call(new bar()) // override print and prints: hello from bar
sir4ju1
quelle
0

Ich kann mir keine normale Situation vorstellen, in der das Setzen von thisArg auf etwas anderes der Zweck der Verwendung von apply ist.

Der Zweck von apply besteht darin, ein Array von Werten an eine Funktion zu übergeben, die diese Werte als Argumente verwenden möchte.

Es wurde im normalen täglichen Gebrauch vom Spread-Betreiber abgelöst.

z.B

// Finding the largest number in an array
`Math.max.apply(null, arr)` becomes `Math.max(...arr)`

// Inserting the values of one array at the start of another
Array.prototype.unshift.apply(arr1, arr2); 
// which becomes 
arr1 = [...arr2, ...arr1]
Daniel Coffman
quelle