Aus Dokumenten verstehe ich, dass .proxy()
dies den Umfang der als Argument übergebenen Funktion ändern würde. Könnte mir bitte jemand das besser erklären? Warum sollten wir das tun?
Aus Dokumenten verstehe ich, dass .proxy()
dies den Umfang der als Argument übergebenen Funktion ändern würde. Könnte mir bitte jemand das besser erklären? Warum sollten wir das tun?
Antworten:
Letztendlich wird sichergestellt, dass der Wert this
einer Funktion der von Ihnen gewünschte Wert ist.
Ein häufiges Beispiel ist ein setTimeout
, das in einem click
Handler stattfindet.
Nimm das:
$('#myElement').click(function() {
// In this function, "this" is our DOM element.
$(this).addClass('aNewClass');
});
Die Absicht ist einfach genug. Wenn darauf myElement
geklickt wird, sollte es die Klasse erhalten aNewClass
. Im Handler befindet sich this
das Element, auf das geklickt wurde.
Aber was ist, wenn wir eine kurze Verzögerung wünschen, bevor wir die Klasse hinzufügen? Wir könnten a verwenden setTimeout
, um dies zu erreichen, aber das Problem ist, dass unabhängig von der Funktion, die wir geben setTimeout
, der Wert this
innerhalb dieser Funktion window
anstelle unseres Elements liegt.
$('#myElement').click(function() {
setTimeout(function() {
// Problem! In this function "this" is not our element!
$(this).addClass('aNewClass');
}, 1000);
});
Was wir stattdessen tun können, ist aufzurufen $.proxy()
und ihm die Funktion und den Wert zu senden, denen wir zuweisen möchten this
, und es wird eine Funktion zurückgegeben, die diesen Wert beibehält.
$('#myElement').click(function() {
// ------------------v--------give $.proxy our function,
setTimeout($.proxy(function() {
$(this).addClass('aNewClass'); // Now "this" is again our element
}, this), 1000);
// ---^--------------and tell it that we want our DOM element to be the
// value of "this" in the function
});
Nachdem wir $.proxy()
die Funktion und den gewünschten Wert angegeben haben this
, wurde eine Funktion zurückgegeben, die sicherstellt, dass sie this
richtig eingestellt ist.
Wie macht es das? Es wird nur eine anonyme Funktion zurückgegeben, die unsere Funktion mit der .apply()
Methode aufruft , mit der der Wert von explizit festgelegt werden kann this
.
Ein vereinfachter Blick auf die zurückgegebene Funktion könnte folgendermaßen aussehen:
function() {
// v--------func is the function we gave to $.proxy
func.apply( ctx );
// ----------^------ ctx is the value we wanted for "this" (our DOM element)
}
Diese anonyme Funktion ist also gegeben setTimeout
, und alles, was sie tut, ist, unsere ursprüngliche Funktion mit dem richtigen this
Kontext auszuführen .
$.proxy(function () {...}, this)
anstatt (function() {...}).call(this)
? Ist da ein Unterschied?
.call
dir rufst du die Funktion sofort auf. Mit $.proxy
ist es so, Function.prototype.bind
als würde eine neue Funktion zurückgegeben. Bei dieser neuen Funktion ist der this
Wert permanent gebunden, sodass sie bei Übergabe an setTimeout
und setTimeout
späterem Aufrufen der Funktion immer noch den richtigen this
Wert hat.
Ohne näher darauf einzugehen (was notwendig wäre, da es sich um den Kontext in ECMAScript, die Kontextvariable this usw. handelt)
Es gibt drei verschiedene Arten von "Kontexten" in ECMA- / Javascript:
Jeder Code wird in seinem Ausführungskontext ausgeführt . Es gibt einen globalen Kontext und es kann viele Instanzen von Funktionskontexten (und Bewertungskontexten) geben. Nun der interessante Teil:
Jeder Aufruf einer Funktion tritt in den Funktionsausführungskontext ein. Ein Ausführungskontext einer Funktion sieht folgendermaßen aus:
Die Aktivierung Object
Scope - Chain
diesen Wert
So ist der dieser Wert ist ein spezielles Objekt , das mit dem Ausführungskontext verwendet ist. In ECMA- / Javascript gibt es zwei Funktionen, die diesen Wert in einem Funktionsausführungskontext ändern können :
.call()
.apply()
Wenn wir eine Funktion foobar()
haben, können wir diesen Wert ändern , indem wir Folgendes aufrufen:
foobar.call({test: 5});
Jetzt konnten wir auf foobar
das Objekt zugreifen, das wir übergeben haben:
function foobar() {
this.test // === 5
}
Genau das jQuery.proxy()
macht es. Es nimmt ein function
und context
(das nichts anderes als ein Objekt ist) und verknüpft die Funktion durch Aufrufen von .call()
und .apply()
und gibt diese neue Funktion zurück.
Das gleiche Ziel kann mit einer selbstausführenden Funktion "Sofort aufgerufener Funktionsausdruck, kurz: IIFE" erreicht werden :
$('#myElement').click(function() {
(function(el){
setTimeout(function() {
// Problem! In this function "this" is not our element!
el.addClass('colorme');
}, 1000);
})($(this)); // self executing function
});
.colorme{
color:red;
font-size:20px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<div id="myElement">Click me</div>
</body>
</html>