Z dokumentów rozumiem, .proxy()że zmieniłoby to zakres funkcji przekazanej jako argument. Czy ktoś mógłby mi to lepiej wyjaśnić? Dlaczego powinniśmy to robić?
Z dokumentów rozumiem, .proxy()że zmieniłoby to zakres funkcji przekazanej jako argument. Czy ktoś mógłby mi to lepiej wyjaśnić? Dlaczego powinniśmy to robić?
Odpowiedzi:
Ostatecznie zapewnia, że wartość this w funkcji będzie wartością, której pragniesz.
Typowym przykładem jest to, setTimeoutktóre ma miejsce wewnątrz clickprocedury obsługi.
Weź to:
$('#myElement').click(function() {
// In this function, "this" is our DOM element.
$(this).addClass('aNewClass');
});
Zamiar jest dość prosty. Po myElementkliknięciu powinien otrzymać klasę aNewClass. Wewnątrz procedury obsługi thisreprezentuje kliknięty element.
Ale co by było, gdybyśmy chcieli krótkiego opóźnienia przed dodaniem klasy? Możemy użyć a, setTimeoutaby to osiągnąć, ale problem polega na tym, że niezależnie od funkcji, jaką damy setTimeout, wartość thiswewnątrz tej funkcji będzie windowzamiast naszego elementu.
$('#myElement').click(function() {
setTimeout(function() {
// Problem! In this function "this" is not our element!
$(this).addClass('aNewClass');
}, 1000);
});
Zatem zamiast tego możemy wywołać $.proxy()i wysłać do niej funkcję i wartość, do której chcemy przypisać this, a zwróci to funkcję, która zachowa tę wartość.
$('#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
});
Więc po tym, jak podaliśmy $.proxy()funkcję i żądaną wartość this, zwróciła ona funkcję, która zapewni, że thisjest poprawnie ustawiona.
Jak to się dzieje? Po prostu zwraca anonimową funkcję, która wywołuje naszą funkcję za pomocą .apply()metody, która pozwala jawnie ustawić wartość this.
Uproszczone spojrzenie na zwracaną funkcję może wyglądać następująco:
function() {
// v--------func is the function we gave to $.proxy
func.apply( ctx );
// ----------^------ ctx is the value we wanted for "this" (our DOM element)
}
Więc ta anonimowa funkcja jest dana setTimeouti wszystko, co robi, to wykonanie naszej oryginalnej funkcji w odpowiednim thiskontekście.
$.proxy(function () {...}, this)zamiast (function() {...}).call(this)? Czy jest jakaś różnica?
.calltobą natychmiast wywołujesz funkcję. W $.proxyprzypadku jest to tak, jakby Function.prototype.bindzwracała nową funkcję. Ta nowa funkcja ma thiswartość trwale związany, tak, że gdy jest on przekazywany do setTimeout, i setTimeoutwywołuje funkcję później, to nadal mają prawidłową thiswartość.
Bez wchodzenia w szczegóły (co byłoby konieczne, ponieważ dotyczy to kontekstu w ECMAScript, tej zmiennej kontekstu itp.)
Istnieją trzy różne typy „kontekstów” w ECMA / JavaScript:
Każdy kod jest wykonywany w swoim kontekście wykonania . Jest jeden kontekst globalny i może istnieć wiele przykładów kontekstów funkcyjnych (i ewaluacyjnych). Teraz interesująca część:
Każde wywołanie funkcji wchodzi w kontekst wykonania funkcji. Kontekst wykonania funkcji wygląda następująco:
Łańcuch zakresu obiektu aktywacji
to wartość
Więc ta wartość jest specjalnym obiektem, który jest powiązany z kontekstem wykonania. W ECMA- / Javascript są dwie funkcje, które mogą zmienić tę wartość w kontekście wykonywania funkcji:
.call()
.apply()
Jeśli mamy funkcję foobar(), możemy zmienić tę wartość, wywołując:
foobar.call({test: 5});
Teraz mogliśmy uzyskać dostęp foobardo przekazanego obiektu:
function foobar() {
this.test // === 5
}
Dokładnie to jQuery.proxy()robi. Pobiera functionand context(który jest niczym innym jak obiektem) i łączy funkcję przez wywołanie .call()lub .apply()i zwraca tę nową funkcję.
Ten sam cel można osiągnąć za pomocą samowykonującej się funkcji „Natychmiastowo wywoływane wyrażenie funkcyjne, w skrócie: IIFE” :
$('#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>