A partir dos documentos, eu entendo que .proxy()
isso mudaria o escopo da função passada como argumento. Alguém poderia me explicar isso melhor? Por que devemos fazer isso?
A partir dos documentos, eu entendo que .proxy()
isso mudaria o escopo da função passada como argumento. Alguém poderia me explicar isso melhor? Por que devemos fazer isso?
Respostas:
O que ele faz é garantir que o valor de this
em uma função seja o valor que você deseja.
Um exemplo comum é setTimeout
aquele que ocorre dentro de um click
manipulador.
Pegue isso:
$('#myElement').click(function() {
// In this function, "this" is our DOM element.
$(this).addClass('aNewClass');
});
A intenção é bastante simples. Quando myElement
é clicado, ele deve receber a turma aNewClass
. Dentro do manipulador this
representa o elemento que foi clicado.
Mas e se quiséssemos um pequeno atraso antes de adicionar a classe? Podemos usar a setTimeout
para realizá-lo, mas o problema é que, independentemente da função que atribuímos setTimeout
, o valor de this
dentro dessa função será em window
vez de nosso elemento.
$('#myElement').click(function() {
setTimeout(function() {
// Problem! In this function "this" is not our element!
$(this).addClass('aNewClass');
}, 1000);
});
Portanto, o que podemos fazer é chamar $.proxy()
, enviando a função e o valor que queremos atribuir this
, e ele retornará uma função que reterá esse valor.
$('#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
});
Então, depois de atribuirmos $.proxy()
a função e o valor que desejamos this
, ele retornou uma função que garantirá que this
seja definida corretamente.
Como isso acontece? Ele apenas retorna uma função anônima que chama nossa função usando o .apply()
método, que permite definir explicitamente o valor de this
.
Uma visão simplificada da função retornada pode parecer com:
function() {
// v--------func is the function we gave to $.proxy
func.apply( ctx );
// ----------^------ ctx is the value we wanted for "this" (our DOM element)
}
Portanto, essa função anônima é atribuída setTimeout
e tudo o que faz é executar nossa função original com o this
contexto apropriado .
$.proxy(function () {...}, this)
vez de (function() {...}).call(this)
? Existe alguma diferença?
.call
você está chamando a função imediatamente. Com $.proxy
, é como Function.prototype.bind
onde ele retorna uma nova função. Essa nova função tem o this
valor permanentemente vinculado, de modo que, quando é passado setTimeout
e setTimeout
chama a função posteriormente, ainda terá o this
valor correto .
Sem entrar em maiores detalhes (o que seria necessário porque se trata de Contexto no ECMAScript, a variável this context etc.)
Existem três tipos diferentes de "contextos" no ECMA- / Javascript:
Todo código é executado em seu contexto de execução . Existe um contexto global e pode haver muitas instâncias de contextos de função (e avaliação). Agora a parte interessante:
Toda chamada de uma função entra no contexto de execução da função. Um contexto de execução de uma função se parece com:
O
escopo do objeto de ativação encadeia
esse valor
Portanto, este valor é um objeto especial relacionado ao contexto de execução. Existem duas funções no ECMA- / Javascript que podem alterar esse valor em um contexto de execução de função:
.call()
.apply()
Se tivermos uma função foobar()
, podemos alterar esse valor chamando:
foobar.call({test: 5});
Agora podemos acessar foobar
o objeto que passamos:
function foobar() {
this.test // === 5
}
É exatamente jQuery.proxy()
isso que faz. É preciso um function
e context
(que é nada mais do que um objeto) e liga a função invocando .call()
ou .apply()
e retorna essa nova função.
O mesmo objetivo pode ser alcançado usando a função de execução automática "Expressão de função imediatamente chamada, curta: 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>