스코프의 지속성
엄밀히 따져보면 스코프가 생성되는 방식이 기존 언어와 다르지는 않다. 하지만 스코프가 지속되는 것은 다른 언어와는 다른 자바스크립트만의 강점 중 하나이다. 자바스크립트에서 이러한 스코프의 지속성이 필요한 이유는 새로운 스코프가 생성되고 스코프 체인을 참조하는 함수를 변수에도 넣을 수 있고, 다른 함수의 인자로 넘겨줄 수도 있으며, 함수의 반환값으로도 활용할 수 있기 때문이다. 즉, 지금 함수가 선언된 곳이 아닌 전혀 다른 곳에서 함수가 호출될 수 있어서, 해당 함수가 현재 참조하는 스코프를 지속할 필요가 있는 것이다.
함수를 이용한 문제해결
지속성을 이해하기 위해 앞의 클릭 이벤트 핸들러 문제를 함수를 이용하여 해결해 본다.
<div id="divScope0">Click me! DIV 0</div>
<div id="divScope1">Click me! DIV 1</div>
<div id="divScope2">Click me! DIV 2</div>
<script>
function setDivClick(index) {
document.getElemetById("divScope" + index).addEventListener(
"click",
function() {
alert("You click div #" + index);
}, false
);
}
var i, len = 3;
for(i=0; i<len; i++) {
setDivClick(i);
}
</script>
위처럼 필요할 때 함수로 분리하는 것은 비동기 처리를 많이 하는 자바스크립트의 특성에서는 중요하게 생각해야 하는 개발 방식이다.
위 소스는 with 구문과 비슷하게 모두 정상으로 출력된다. 별도의 function을 추가했으므로 with 구문과 똑같은 개념으로 스코프가 생성되고 지속된다. 따라서 스코프 체인은 비슷하게 나온다.
하지만, 내부적으로 다른점이 있다면, 일단 with가 가지고 있는 모호성을 배제할 수 있고, 완벽하게 이벤트 처리를 위한 별도의 스코프를 하나 만들어서 사용하게 된다.
클로저를 활용한 문제해결
이처럼 함수를 생성하는 것을 조금 다르게 자바스크립트의 특징 중 하나인 클로저를 활용하여 해결할 수도 있다.
<div id="divScope0">Click me! DIV 0</div>
<div id="divScope1">Click me! DIV 1</div>
<div id="divScope2">Click me! DIV 2</div>
<script>
var i, len = 3;
for(i=0; i<len; i++) {
document.getElementById("divScope" + i).addEventListener(
"click",
(function (index) {
return function() {
alert("You clicked div #" + index);
};
}(i)),
false);
}
</script>
이러한 기법은 자바스크립트에서 많이 사용되고 있고 응용 범위도 넓으므로 개발하면서 쉽게 적용할 수 있도록 익혀두면 유용하다.
약간 복잡해 보이고 with 구문과 비슷하게 생각할 수 있지만, with 구문과는 다르게 구문 안에서 스코프 체인을 function으로 만들고 있다.
/* 이해하기
9~13번 줄에서 콜백 함수를 할당하는 인자를 보면, 9번 줄의 익명 함수는 index라는 파라미터를 받으며, 그 파라미터는 13번 줄에 있는 i의 값을 넘겨준다. 이는 두 단계로 나눠서 생각해보면 쉽다.
- var fnuc = function(index) { /* 생략 */ };
- var returnValue = func(i);
- returnValue = (function (index) { /* 생략 */ }(i));
위 소스에서 1~2번 줄을 한 줄로 표현하면 3번 줄과 같다. 이는 자바스크립트에서 매우 자주 등장하는 함수의 활용 방법으로 IIFE(Immediate Invoke Function Expression)라고 불린다. (즉시 호출 함수)
이러한 표현 방식은 스코프 체인을 생성해서 클로저를 활용하는 데 매우 유용하게 쓰이며, 다양한 자바스크립트 라이브러리들에서도 기본으로 활용하는 기법 중 하나이다.
간단히 풀이하면, 1번 줄은 익명 함수를 func 변수에 넣고 2번 줄은 이 func 변수에 i의 값을 넘겨준다. 이것을 3번 줄에서는 function(index) {} 부분과 (i)부분을 하나로 합쳐서, 함수를 선언하고 바로 호출한다.
*/
9번 줄과 13번 줄은 IIFE 표현 방식을 따르고 있다. 그리고 바로 다음 10번 줄에서는 새로운 함수를 하나 선언해서 반환한다. 반환된 함수는 9번 줄의 index 변수를 상위 스코프 체인에 추가한 뒤, addEventListener() 함수의 2번째 인자로 들어간다.
새로운 스코프가 클릭 이벤트 핸들러의 콜백 함수의 상위에 추가되면서 문제를 해결하고 있는데, 이것은 클로저의 아주 기초적인 활용 방법이다.
'가짜 개발자 Shiro > javaScript' 카테고리의 다른 글
클로저 - 2 (0) | 2020.02.14 |
---|---|
[쉬어가기] Return (0) | 2020.02.03 |
클로저 - 1 (0) | 2020.01.22 |
스코프 - 2 (0) | 2020.01.15 |
스코프 (0) | 2020.01.14 |