2014-06-10 4 views
0

다른 StackOverflow 질문 (Creating a clickable grid in a web browser)에서 답변자는이를 http://jsfiddle.net/6qkdP/2/으로 게시했습니다.지원 기능 콜백 이해

JavaScript를 배우는 동안 비슷한 것을 시도했지만이 답변은 답변보다 많은 질문을 제공했습니다. 이제는 함수를 반환하는 함수의 개념을 이해하고 있다고 생각합니다. 그러나, JS가 jsfiddle 링크를 게시 라인 15 일 ...

날 혼란, 그리고 그 이유는, 함수가 생성됩니다

function clickableGrid(rows, cols, callback){...} 

그것은 간단 보인다 행과 열의 수를 전달 , 어떤 함수가 호출되는지를 전달합니다 (맞습니까?). 위의 두 번째 줄에서는 함수를 호출하고 콜백의 경우에는 몇 가지 (el, row, col, i)를 받아들이고 콘솔에서 출력을 제공하는 함수를 전달합니다.

var grid = clickableGrid(10,10,function(el,row,col,i){...} 

모두 이해하기 쉬운 것처럼 보입니다 (물론, 올바르게 이해한다고 가정하면!). 그러나 다음 줄 24에서 시작하는이 비트는 나를 혼란스럽게합니다 :

생성되는 요소에 대한 클릭 이벤트 리스너를 생성합니다. 이 이벤트 리스너는 (...

, 다른 함수를 반환 (기능 (엘, R, C, I) {

을 ... '클릭'4 개 매개 변수 ... cell.addEventListener을 받아 새로운 함수를 호출

   return function(){ 
(?) 그 같은 4 개 매개 변수를 전달하는 메인 함수의 콜백입니다

..., ...

    callback(el,r,c,i); 
       } 

... 다음이 비트는 클릭시 전달되는 것입니다 이벤트?

  })(cell,r,c,i),false); 

맞습니까? 그것은 나에게 지나치게 혼란스럽게 보입니다 ... 예를 들어, 같은 매개 변수를 받아들이는 함수 하나가 왜 만들어 졌는지, 그리고 이러한 콜백을 모두 사용하지 않고도 바로 요소의 스타일을 변경한다는 것을 이해하지 못합니다. 나는 무언가를 놓치고 있으며, 여기서 더 경험 많은 사람들이 내가 이해하지 못하는 것이 무엇인지에 대한 정보를 제공하기를 희망합니다.

감사합니다. JSFiddle가 다운 된 경우

코드 :

var lastClicked; 
var grid = clickableGrid(10,10,function(el,row,col,i){ 
    console.log("You clicked on element:",el); 
    console.log("You clicked on row:",row); 
    console.log("You clicked on col:",col); 
    console.log("You clicked on item #:",i); 

    el.className='clicked'; 
    if (lastClicked) lastClicked.className=''; 
    lastClicked = el; 
}); 

document.body.appendChild(grid); 

function clickableGrid(rows, cols, callback){ 
    var i=0; 
    var grid = document.createElement('table'); 
    grid.className = 'grid'; 
    for (var r=0;r<rows;++r){ 
     var tr = grid.appendChild(document.createElement('tr')); 
     for (var c=0;c<cols;++c){ 
      var cell = tr.appendChild(document.createElement('td')); 
      cell.innerHTML = ++i; 
      cell.addEventListener('click',(function(el,r,c,i){ 
       return function(){ 
        callback(el,r,c,i); 
       } 
      })(cell,r,c,i),false); 
     } 
    } 
    return grid; 
} 

답변

0

확인,이 부분 :

cell.addEventListener('click',(function(el,r,c,i){ 
    return function(){ 
     callback(el,r,c,i); 
    } 
})(cell,r,c,i),false); 

하는 것은 기본적으로이 일을 수 있습니다 :

cell.addEventListener('click',eventHandler,false); 

그래서 이벤트 핸들러가하는 대체 부품이,이 이벤트 핸들러로 함수를 반환해야 뭐든간에. 따라서 명확성을 위해 다시 작성해 보겠습니다 :

var eventHandler = (function(el,r,c,i){ 
    return function(){ 
     callback(el,r,c,i); 
    } 
})(cell,r,c,i); 
cell.addEventListener('click',eventHandler,false); 

이제 eventHandler 비트는 자체 호출 함수입니다. 또한 함수 팩터 리 (함수를 반환)입니다. 자, eventHandlerFactory라고 부르 자. 이제 명확하게 다시 작성하십시오.

function eventHandlerFactory (el,r,c,i) { 
    return function(){ 
     callback(el,r,c,i); 
    } 
} 
var eventHandler = eventHandlerFactory(cell,r,c,i); 
cell.addEventListener('click',eventHandler,false); 

이제 훨씬 쉽게 읽을 수 있습니다.eventHandlerFactory는 anonymous 함수를 반환하고,이 함수는 eventHandler에 할당됩니다 (지금은 익명 함수의 내용을 무시하십시오). eventHandlerFactory에 의해 생성 된 eventHandler 함수는 셀의 onclick 이벤트에 할당됩니다. 셀을 클릭하면 eventHandler 함수가 실행됩니다. eventHandler 함수의 내용 (지금 무시할 수 있음)은 이전에 제공 한 콜백 함수에 대한 호출입니다.

질문은 왜 functionHandler를 함수 팩터 리의 다른 레이어에 래핑하는 데 추가되는 복잡성입니까? 그 대답은 루프 문제의 고전적인 폐쇄입니다. 변수 r, c, icell은 루프에서 클로저로 캡쳐되며 이는 모든 셀이 동일한 변수를 공유하기 때문에 문제가됩니다. 자바 스크립트에서 클로저를 깨는 유일한 방법은 참조를 함수 인수로 전달하는 것입니다. 따라서 추가 기능 팩토리는 클로저를 해제하여 각 셀이 변수에 대한 올바른 값으로 작동하도록 보장합니다.

0
cell.addEventListener('click',(function(el,r,c,i){ 
       return function(){ 
        callback(el,r,c,i); 
       } 
      })(cell,r,c,i),false); 

자바 스크립트 변수는 함수가 자신의 코드를 scoped.IE 있습니다 서면과 동일합니다. 하나의 다른 기능을 만들기 위해 필요한 루프를 반복 할 때마다 각 변수의 값을 유지하기 위해

function clickableGrid(rows, cols, callback){ 
    var i,grid,r,c,tr,cell; 
    ... 

엘은, R이 C, 난 적절히 폐쇄 만들어 범위된다 scope.Therefore.

그가 코드를 작성하지 않았다면. 모든 콜백은 동일한 셀, r, c, i 값, 즉 2 루프의 마지막 반복에서 값을 갖게됩니다.

그것이 immediatly 호출 기능

cell.addEventListener('click', function(){ 
        callback(cell,r,c,i); 
       } 
      ,false); 

모든 단지에만 콜백에게 마지막 셀, 마지막 R, C를 전달합니다 귀하의 클릭이, 내가 값 모든 루프가 완료 제거하려고합니다.

정확히 쓰는 것과 같습니다.

var x=5; 

window.getX=function(){ 
    return x; 
} 

x = 6; 

console.log(getX()) // 6 

x getX 함수 내부는 항상 x의 마지막 값을 나타냅니다.

하지만 getX가 immediatly 호출 함수 표현식 (인생)의 폐쇄에 X를 의미에서 나는

var x=5; 

(function(x){ 

window.getX=function(){ 
    return x; 
} 

}(x)) 

x = 6; 

console.log(getX()) // 5 

X를 작성하는 경우.

더 많은 것들이 있으며 처음부터 보이는 것보다 훨씬 복잡합니다. 전체 그림을 얻으려면 책 "Javascript Allongé"를 가져옵니다.

0

OK, 그래서 이것은 흥미로운 부분입니다 :이 밖으로 시도하는 경우

cell.addEventListener('click', 
    function(){ 
     callback(cell,r,c,i); 
    }, 
false); 

, 항상 당신은 클릭 "말할 것이다 : 더 순진 구현은 다음과 같을 수

cell.addEventListener('click', 
    (function(el,r,c,i){ 
     return function(){ 
      callback(el,r,c,i); 
     } 
    })(cell,r,c,i), 
    false); 

셀 # 100 ". 이는 변수 때문에 , R, C, I 캡처되어있다 종결자가 아닌 사본. 즉, 다음 루프 반복에서 값이 변경되면 에 사용 된 값인 모든 콜백이 변경됩니다.

이것은 매개 변수로 변수를 취하고 즉시 실행되어 효과적으로 새로운 지역 변수를 만드는 함수 안에 클로저를 래핑함으로써 방지 할 수 있습니다.

패턴

(function(args){ 
    … 
})(stuff); 

일반적 내부 새로운 변수 영역을 만들 JS에서 사용된다.