for 루프를 사용하고 값을 전달하는 addEventListener
이 질문에 이미 답변이 있습니다.
for 루프를 사용하여 여러 객체에 이벤트 리스너를 추가하려고하는데 모든 리스너가 동일한 객체-> 마지막 객체를 대상으로합니다.
모든 인스턴스에 대해 boxa와 boxb를 정의하여 리스너를 수동으로 추가하면 작동합니다. 내가 바라던 방식으로 작동하지 않는 것이 addEvent for 루프라고 생각합니다. 어쩌면 나는 모두 잘못된 접근 방식을 사용했을 것입니다.
class = "container"중 4 개를 사용한 예 컨테이너 4에 대한 트리거는 예상대로 작동합니다. 컨테이너 1,2,3 트리거 이벤트를 컨테이너 4에서 트리거하지만 트리거가 이미 활성화 된 경우에만 해당됩니다.
// Function to run on click:
function makeItHappen(elem, elem2) {
var el = document.getElementById(elem);
el.style.backgroundColor = "red";
var el2 = document.getElementById(elem2);
el2.style.backgroundColor = "blue";
}
// Autoloading function to add the listeners:
var elem = document.getElementsByClassName("triggerClass");
for (var i = 0; i < elem.length; i += 2) {
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function() {
makeItHappen(boxa, boxb);
}, false);
elem[k].addEventListener("click", function() {
makeItHappen(boxb, boxa);
}, false);
}
<div class="container">
<div class="one" id="box1">
<p class="triggerClass">some text</p>
</div>
<div class="two" id="box2">
<p class="triggerClass">some text</p>
</div>
</div>
<div class="container">
<div class="one" id="box3">
<p class="triggerClass">some text</p>
</div>
<div class="two" id="box4">
<p class="triggerClass">some text</p>
</div>
</div>
폐쇄! :디
이 고정 코드는 의도 한대로 작동합니다.
// Function to run on click:
function makeItHappen(elem, elem2) {
var el = document.getElementById(elem);
el.style.backgroundColor = "red";
var el2 = document.getElementById(elem2);
el2.style.backgroundColor = "blue";
}
// Autoloading function to add the listeners:
var elem = document.getElementsByClassName("triggerClass");
for (var i = 0; i < elem.length; i += 2) {
(function () {
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function() { makeItHappen(boxa,boxb); }, false);
elem[k].addEventListener("click", function() { makeItHappen(boxb,boxa); }, false);
}()); // immediate invocation
}
<div class="container">
<div class="one" id="box1">
<p class="triggerClass">some text</p>
</div>
<div class="two" id="box2">
<p class="triggerClass">some text</p>
</div>
</div>
<div class="container">
<div class="one" id="box3">
<p class="triggerClass">some text</p>
</div>
<div class="two" id="box4">
<p class="triggerClass">some text</p>
</div>
</div>
이 문제가 해결되는 이유는 무엇입니까?
for(var i=0; i < elem.length; i+=2){
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false);
elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false);
}
Is actually non-strict JavaScript. It's interpretted like this:
var i, k, boxa, boxb;
for(i=0; i < elem.length; i+=2){
k = i + 1;
boxa = elem[i].parentNode.id;
boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false);
elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false);
}
Because of variable hoisting, the var
declarations get moved to the top of the scope. Since JavaScript doesn't have block scope (for
, if
, while
etc.) they get moved to the top of the function. Update: as of ES6 you can use let
to get block scoped variables.
When your code runs the following happens: in the for
loop you add the click callbacks and you assign boxa
, but its value gets overwritten in the next iteration. When the click event fires the callback runs and the value of boxa
is always the last element in the list.
Using a closure (closing the values of boxa
, boxb
etc) you bind the value to the scope of the click handler.
Code analysis tools such JSLint or JSHint will be able to catch suspicious code like this. If you're writing a lot of code it's worthwhile to take the time to learn how to use these tools. Some IDEs have them built-in.
You facing the scope/closure problem as function(){makeItHappen(boxa,boxb);}
boxa and boxb references then always the last one element(s).
To solve the issue:
function makeItHappenDelegate(a, b) {
return function(){
makeItHappen(a, b)
}
}
// ...
elem[i].addEventListener("click", makeItHappenDelegate(boxa,boxb), false);
You can use Function Binding.You dont need use closures.See below:
Before:
function addEvents(){
var elem = document.getElementsByClassName("triggerClass");
for(var i=0; i < elem.length; i+=2){
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false);
elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false);
}
}
After:
function addEvents(){
var elem = document.getElementsByClassName("triggerClass");
for(var i=0; i < elem.length; i+=2){
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false);
elem[k].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false);
}
}
I also had this problem a while ago. I solved it by using a "adds" function outside the loop, to assign events, and it worked perfectly.
Your script should look like.
function addEvents(){
var elem = document.getElementsByClassName("triggerClass");
for(var i=0; i < elem.length; i+=2){
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
//- edit ---------------------------|
adds(boxa, boxb);
}
}
//- adds function ----|
function adds(obj1, obj2){
obj1.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false);
obj2.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false);
}
//- end edit -----------------------|
function makeItHappen(elem, elem2){
var el = document.getElementById(elem);
el.style.transform = "flip it";
var el2 = document.getElementById(elem2);
el2.style.transform = "flip it";
}
It's because of closures.
Check this out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake
The sample code and your code is essentially the same, it's a common mistake for those don't know "closure".
To put it simple, when your create a handler function inside addEvents()
, it does not just accesses the variable i
from the addEvents()
's environment, but it also "remembers" i
.
And because your handler "remembers" i
, the variable i
won't vanish after addEvents()
was executed.
So when the handler is called, it will use the i
but the variable i
is now, after the for-loop, 3.
참고URL : https://stackoverflow.com/questions/19586137/addeventlistener-using-for-loop-and-passing-values
'Program Tip' 카테고리의 다른 글
Rails .where 대 .find (0) | 2020.10.21 |
---|---|
java.sql.Timestamp 시간대는 특정입니까? (0) | 2020.10.21 |
iOS / OSX 프레임 워크 생성 : 다른 개발자에게 배포하기 전에 코드 서명이 필요합니까? (0) | 2020.10.21 |
Android SDK 버전을 검색하는 방법은 무엇입니까? (0) | 2020.10.21 |
Java에서 문자열에 매핑 (0) | 2020.10.21 |