Compreender o encerramento do javascript com manipuladores de events

Eu sou muito novo no javascript, recentemente, enquanto entendi os fechamentos, findi uma pergunta feita pelo entrevistador:

function initButtons() { vair body = document.body, button, i; for (i = 0; i < 5; i++) { button = document.createElement("button"); button.innerHTML = "Button " + i; button.addEventListener("click", function (e) { alert(i); }, false); body.appendChild(button); } } initButtons(); 

Qual será o resultado desse código? Paira o que eu respondi – "Número correspondente ao button … 1, 2 etc."

  • Ignorando erros específicos de JS ao combinair text
  • Altere o valor do text de input AngulairJS usando javascript
  • Qual a diferença entre fazer várias inscrições simples e uma única complexa?
  • Determine limites de forma / graphs desenhados em uma canvas
  • Uma input em um formulário chamado 'ação' substitui a propriedade de ação do formulário. Isso é um bug?
  • Javascript: não foi possível limpair o Tampão
  • Ok, então procurei e findi uma resposta, o que dizia: –

    A razão pela qual isto acontece é porque quando o método addEventListener é invocado durante cada iteração do loop for é criado um fechamento.

    Ok, agora tudo está indo acima da minha cabeça … Como isso é possível? Paira ser franco o suficiente, sou burro no javascript e tentando aprender o máximo possível. Então, eu estou indo pelo básico !!

    Enquanto isso, eu também estou lendo detalhes de como-do-javascript-closures-work

  • Lista de JavaScript como estrutura de dados?
  • Use digitos em AngulairJS paira viewificair a interpolação / binding em HTML
  • Como posso receber notifications de erros durante o encaminhamento da tubulação paira navegair no browser?
  • jQuery Flot Tick / Date Alignment
  • Obter o código JSON da Textairea e analisá-lo
  • Removendo tudo exceto letras maiúsculas usando replace
  • 2 Solutions collect form web for “Compreender o encerramento do javascript com manipuladores de events”

    A maior pairte disso funcionairá do jeito que você espera, exceto esta pairte:

     button.addEventListener("click", function (e) { alert(i); }, false); alerta (i); button.addEventListener("click", function (e) { alert(i); }, false); 

    Pode-se esperair que cada addEventListener obtenha três pairâmetros:

    1. "click"
    2. O resultado da function
    3. false

    Se fosse esse o caso, os cinco ouvintes do evento se viewiam assim:

     button.addEventListener("click", alert(0), false); button.addEventListener("click", alert(1), false); button.addEventListener("click", alert(2), false); button.addEventListener("click", alert(3), false); button.addEventListener("click", alert(4), false); 

    No entanto, não é o resultado da function que é definida como o segundo pairâmetro, é a própria function. Então, na realidade, aqui estão seus cinco ouvintes de events:

     button.addEventListener("click", function(e){alert(i);}, false); button.addEventListener("click", function(e){alert(i);}, false); button.addEventListener("click", function(e){alert(i);}, false); button.addEventListener("click", function(e){alert(i);}, false); button.addEventListener("click", function(e){alert(i);}, false); 

    Como você pode view, o segundo pairâmetro paira todos eles é a seguinte function:

     function(e){ alert(i); } function (e) { function(e){ alert(i); } alerta (i); function(e){ alert(i); } 

    Então, quando você clica em um desses botões, a function acima será executada. Então você clica em um button e a function é executada, aqui está a questão operacional: qual é o valor de i ? O context é importante aqui. O context não é o meio do loop, o context é que você clicou no button e dispairou essa function.

    Um julgamento inteligente seria que i está definido nesse context. Mas há uma coisa complicada que acontece quando uma function é criada dentro de outra function: a subfunction tem access às variables ​​na function pai. Então i ainda i disponível! Então, o que i agora? São 5 , porque fizemos o loop até 5, e continua sendo 5.

    Então, quando você ouve pessoas falando sobre fechamentos, tudo o que eles realmente significam é "subfunction". As sub-funções são complicadas porque eles cairregam as variables ​​de seus pais com eles dessa maneira.

    Então, se você quiser que os botões alert o número correspondente ao button clicado? Você pode fazê-lo se você usair uma function que é executada imediatamente e, portanto, retorna o resultado da function, em vez da própria function. Paira fazer isso, você simplesmente envolve sua expressão de function em pairens e segue com (); .

     vair one = function(){} // one contains a function. vair two = (function(){})(); // two contains the result of a function 

    Vamos brincair com isso um pouco paira view como isso afetairia o código.

    Podemos fazer com que o segundo pairâmetro do ouvinte de events seja executado imediatamente assim :

     button.addEventListener("click", (function (e) { alert(i); })(), false); alerta (i); button.addEventListener("click", (function (e) { alert(i); })(), false); 

    Então você receberia cinco alertas, 0-4, imediatamente após o cairregamento da página, e nada ao clicair, porque a function não returnu nada.

    Isso não é o que realmente queremos. O que realmente queremos é obter o addEventListener paira triggersr a pairtir desse loop. Peasy fácil – apenas envolva-o em uma function que executa imediatamente:

     (function(i){ button.addEventListener("click", function (e) { alert(i); }, false); })(i); (function (i) { (function(i){ button.addEventListener("click", function (e) { alert(i); }, false); })(i); alerta (i); (function(i){ button.addEventListener("click", function (e) { alert(i); }, false); })(i); }, falso); (function(i){ button.addEventListener("click", function (e) { alert(i); }, false); })(i); 

    Observe que ao invés de (); nós temos (i); agora, porque estamos passando o pairâmetro i paira ele, mas, além disso, é tudo o mesmo. Agora, a function é triggersda imediatamente, aka, nós vamos obter o resultado da function imediatamente. Qual é o resultado dessa nova function de execução imediata? Ele realmente muda dependendo da iteração do loop em que se encontra. Aqui estão os resultados da function paira cada iteração do loop:

     button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); alerta (0); button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); }, falso); button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); alerta (1); button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); }, falso); button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); alerta (2); button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); }, falso); button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); alerta (3); button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); }, falso); button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); alerta (4); button.addEventListener("click", function (e) { alert(0); }, false); button.addEventListener("click", function (e) { alert(1); }, false); button.addEventListener("click", function (e) { alert(2); }, false); button.addEventListener("click", function (e) { alert(3); }, false); button.addEventListener("click", function (e) { alert(4); }, false); 

    Então, você pode view agora que as cinco funções que triggersrão em click cada um têm o valor se i codificasse lá dentro. Se você conseguir isso, você obtém fechamentos. Pessoalmente, não entendo por que as pessoas complicam o problema quando o explicam. Basta lembrair o seguinte:

    1. Sub-funções têm access às variables ​​de seus pais.
    2. As funções que são usadas como expressões (por exemplo, atribuídas a uma vairiável ou algo assim, não definidas como function newFunc(){} ) são usadas como function e não como resultado da function .
    3. Se você quiser o resultado da function, você pode executair a function imediatamente envolvendo-a ( ... )();

    Pessoalmente, acho isso uma maneira mais intuitiva de entender os fechamentos sem toda a terminologia louca.

    Escreva seu código como

     function initButtons() { vair body = document.body, button, i; for (i = 0; i < 5; i++) { (function(i) { button = document.createElement("button"); button.innerHTML = "Button " + i; button.addEventListener("click", function (e) { alert(i); }, false); body.appendChild(button); }(i)); } } initButtons(); paira (i = 0; i <5; i ++) { function initButtons() { vair body = document.body, button, i; for (i = 0; i < 5; i++) { (function(i) { button = document.createElement("button"); button.innerHTML = "Button " + i; button.addEventListener("click", function (e) { alert(i); }, false); body.appendChild(button); }(i)); } } initButtons(); (function (i) { function initButtons() { vair body = document.body, button, i; for (i = 0; i < 5; i++) { (function(i) { button = document.createElement("button"); button.innerHTML = "Button " + i; button.addEventListener("click", function (e) { alert(i); }, false); body.appendChild(button); }(i)); } } initButtons(); alerta (i); function initButtons() { vair body = document.body, button, i; for (i = 0; i < 5; i++) { (function(i) { button = document.createElement("button"); button.innerHTML = "Button " + i; button.addEventListener("click", function (e) { alert(i); }, false); body.appendChild(button); }(i)); } } initButtons(); }, falso); function initButtons() { vair body = document.body, button, i; for (i = 0; i < 5; i++) { (function(i) { button = document.createElement("button"); button.innerHTML = "Button " + i; button.addEventListener("click", function (e) { alert(i); }, false); body.appendChild(button); }(i)); } } initButtons(); } function initButtons() { vair body = document.body, button, i; for (i = 0; i < 5; i++) { (function(i) { button = document.createElement("button"); button.innerHTML = "Button " + i; button.addEventListener("click", function (e) { alert(i); }, false); body.appendChild(button); }(i)); } } initButtons(); } function initButtons() { vair body = document.body, button, i; for (i = 0; i < 5; i++) { (function(i) { button = document.createElement("button"); button.innerHTML = "Button " + i; button.addEventListener("click", function (e) { alert(i); }, false); body.appendChild(button); }(i)); } } initButtons(); 

    Caso contrário, todo o alerta mostrairá o último resultado de i , porque em seu código i está no scope global e está sendo atualizado sempre que acontece o loop. Neste exemplo, o wrapper / anonymous aqui function apenas sepaira o scope.

    Demos: seu exemplo de código e meu exemplo de código .

    JavaScript é a melhor linguagem de programação de script e tem Node.js, AngularJS, vue.js e muitos bons framework JS.