Da documenti ho capito che .proxy()
cambierebbe l'ambito della funzione passata come argomento. Qualcuno potrebbe spiegarmi meglio? Perché dovremmo farlo?
Da documenti ho capito che .proxy()
cambierebbe l'ambito della funzione passata come argomento. Qualcuno potrebbe spiegarmi meglio? Perché dovremmo farlo?
Risposte:
Ciò che alla fine fa è assicurarsi che il valore di this
in una funzione sia il valore desiderato.
Un esempio comune è in un setTimeout
che si svolge all'interno di un click
gestore.
Prendi questo:
$('#myElement').click(function() {
// In this function, "this" is our DOM element.
$(this).addClass('aNewClass');
});
L'intenzione è abbastanza semplice. Quando myElement
viene cliccato, dovrebbe ottenere la classe aNewClass
. All'interno del gestore this
rappresenta l'elemento su cui è stato fatto clic.
E se volessimo un breve ritardo prima di aggiungere la classe? Potremmo usare a setTimeout
per realizzarlo, ma il guaio è che qualunque sia la funzione che diamo setTimeout
, il valore this
all'interno di quella funzione sarà window
invece del nostro elemento.
$('#myElement').click(function() {
setTimeout(function() {
// Problem! In this function "this" is not our element!
$(this).addClass('aNewClass');
}, 1000);
});
Quindi quello che possiamo fare, invece, è chiamare $.proxy()
, inviandogli la funzione e il valore che vogliamo assegnare this
e restituirà una funzione che manterrà quel valore.
$('#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
});
Quindi dopo che abbiamo dato $.proxy()
la funzione e il valore che desideriamo this
, ha restituito una funzione che garantirà che this
sia impostata correttamente.
Come lo fa? Restituisce semplicemente una funzione anonima che chiama la nostra funzione utilizzando il .apply()
metodo, che consente di impostare esplicitamente il valore di this
.
Uno sguardo semplificato alla funzione che viene restituita può apparire come:
function() {
// v--------func is the function we gave to $.proxy
func.apply( ctx );
// ----------^------ ctx is the value we wanted for "this" (our DOM element)
}
Quindi questa funzione anonima è data a setTimeout
, e tutto ciò che fa è eseguire la nostra funzione originale nel giusto this
contesto.
$.proxy(function () {...}, this)
piuttosto che (function() {...}).call(this)
? C'è una differenza?
.call
te stai chiamando immediatamente la funzione. Con $.proxy
, è come Function.prototype.bind
dove restituisce una nuova funzione. Quella nuova funzione ha il this
valore associato in modo permanente, in modo che quando viene passato a setTimeout
, e setTimeout
chiama la funzione in seguito, avrà ancora il this
valore corretto .
Senza entrare nel dettaglio (ciò sarebbe necessario perché si tratta di Contesto in ECMAScript, questa variabile di contesto ecc.)
Esistono tre diversi tipi di "contesti" in ECMA- / Javascript:
Ogni codice viene eseguito nel suo contesto di esecuzione . Esiste un contesto globale e possono esserci molti casi di contesti di funzione (e valutazione). Ora la parte interessante:
Ogni chiamata di una funzione entra nel contesto di esecuzione della funzione. Un contesto di esecuzione di una funzione è simile a:
L'ambito Activation Object
Scope
questo valore
Quindi questo valore è un oggetto speciale correlato al contesto di esecuzione. Esistono due funzioni in ECMA- / Javascript che possono modificare questo valore in un contesto di esecuzione della funzione:
.call()
.apply()
Se abbiamo una funzione foobar()
possiamo cambiare questo valore chiamando:
foobar.call({test: 5});
Ora potremmo accedere foobar
all'oggetto in cui siamo passati:
function foobar() {
this.test // === 5
}
Questo è esattamente ciò che jQuery.proxy()
fa. Prende un function
e context
(che non è altro che un oggetto) e collega la funzione invocando .call()
o .apply()
e restituisce quella nuova funzione.
Lo stesso obiettivo può essere raggiunto utilizzando una funzione di auto-esecuzione "Espressione di funzione immediatamente richiamata, breve: 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>