ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JS/스코프] 자바스크립트 스코프(scope)와 즉시실행함수(IIFE)
    Frontend 2019. 5. 2. 16:02

    스코프(scope)

    스코프란 일종의 "범위"와 같은 것이다. 어떤 변수를 선언하였을 때, 그 변수에 접근할 수 있는 범위라고 생각하면 쉽니다. 스코프에는 Global(전역)Local(지역)이 있는데, Global scope는 말 그대로 어떤 함수에 종속되어있지 않고 어디서나 접근할 수 있는 전역 범위를 말한다. 반면, Local scope는 어떤 함수나 블록 단위로 국한되는 범위를 말한다.

     

    만약에 Global scope에 어떤 변수가 선언되었다면, 그 변수는 Global Variable(전역 변수)가 된다.

    반면, 어떤 변수가 Local scope에 선언되었다면, Local Variable(지역 변수)가 된다.

     

     

    위 그림에서 파란색 영역이 Global scope, 보라색 영역이 Local scope이다.

    파란색영역에 있는 변수 a는 Global variable(전역변수)로 함수 내부든 외부든 어디서든지 접근가능하다.

    즉, 보라색 영역에서도 변수 a의 값을 출력할 수 있다.

    반면, 보라색 영역에 있는 Local variable(지역변수)은 외부에서는 접근할 수가 없다.

     

    즉, 내부(Local Scope)에서 외부(Gloal scope)는 접근이 가능하지만

    반대로 외부(Global Scope)에서 내부(Local Scope)는 접근이 불가능하다.

     

    var a = 1;
    var c = 3;
    
    function foo() {
        var b = 2;
        var c = 1;
    
        console.log(a);	// 1
        console.log(b);	// 2
        console.log(c);	// 1
    }
    
    foo();
    
    console.log(b);	// error - cannot access 'b'
    console.log(c);	// 3

    위 코드에서 함수 foo()를 실행하였을 때,

    foo()함수 안에서 b를 console창에 출력하면 2가 출력되지만

    foo()함수 밖에서 b를 출력하려고 하면 에러가 뜬다.

     

    왜냐면 변수 b가 함수 foo() scope에 속하는 지역변수이기 때문이다.

     

     

    자바스크립트에서 변수를 선언할 때 var / let / const 이렇게 3가지를 쓸 수 있는데,

    그 중에서 가장 많이 사용하는 var는 스코프가 함수 단위로 정해진다.

     

    function foo() {
        var a = 10;
        for(var i=0; i<a; i++) {
            console.log(i);
        }
        console.log(i);	// 10 -> for문 밖에서도 변수 i는 살아있음
    }
    foo();

    위 코드에서 변수 i는 for문의 초기식에서 선언되었지만,

    for문 밖에서도 여전히 살아있다.

    foo라는 함수 스코프 범위에 있기 때문이다.

     

    만약에 foo()함수 밖에서 console.log(i)를 했다면 에러가 떴을 것이다.

    (반면에 let과 const는 블록 단위로 스코프가 정해진다.

    즉, 위 코드에서 var를 let으로 바꾸면 i는 for문 안에서만 접근할 수 있기 때문에

    for문 밖의 console.log(i) 부분에서는 에러가 떴을 것이다.)

     

     


    즉시실행함수 (Immediately Invoked Function Expression, IIFE)

    만약에 어떤 변수를 전역 변수(Global variable)로 선언한다고 해보자. 이 전역 변수는 선언하는 즉시, 전역 공간의 가장 상위 객체, 즉 전역 객체(Global Object)인 window 객체의 속성으로 추가된다.

     

    이를 확인해보려면 var a = 1;이라고 전역 변수를 선언 및 할당한 후, console창에 window.a를 출력해보자. 1이 바로 출력될 것이다. 이러한 특성으로 인해 전역 변수의 사용은 되도록이면 지양하면 좋은데, 그 이유는 다음과 같다.

     

    var color = 'blue';
    
    console.log('I like ' + color);		// I like blue
    
    setTimeout(function() {
        console.log('I like ' + color);	// I like blue
    }, 1000);

    어떤 전역 스코프에 위와 같은 코드를 작성했다고 해보자.

    실행하면 콘솔창에 I like blue가 뜰 것이고 1초 후, I like blue가 또 뜰 것이다.

     

     

    그런데 만약 누군가가 다른 전역 공간에 이런 스크립트를 작성했다고 해보자.

    var color = 'blue';
    
    console.log('I like ' + color);		// 1번째 실행
    
    setTimeout(function() {
        console.log('I like ' + color);	// 3번째 실행
    }, 1000);
    
    var color = 'red';
    
    console.log('I like ' + color);		// 2번째 실행
    
    setTimeout(function() {
        console.log('I like ' + color);	// 4번째 실행
    }, 1000);

     

    먼저 "I like blue"가 실행되고 setTimeout함수를 만나는데, 이 함수는 1초 뒤에 실행하는 함수이므로 대기열로 빠진다. 그리고나서 전역변수에 이미 color라는 변수가 선언되어있는데, 똑같은 이름의 전역 변수가 다시 선언되므로 기존에 선언된 color = "blue"는 무시되고 새로운 color = "red"로 덮어써지므로, blue대신 red로 계속 출력되게 된다.

     

    실행결과는 다음과 같다.

     

    이렇게 변수를 전역 공간에 선언하면 모든 공간에서 그 변수에 접근이 가능하기 때문에

    여러 사람과 작업할 때, 혹은 혼자 작업하더라도 프로그램이 복잡해질 때

    변수가 중복되거나 다른 작업에 영향을 줘서 오류가 발생할 가능성이 매우 높아진다.

     

    이러한 경우에 우리는 즉시실행함수를 사용하여 강제로 변수의 범위를 제한시킬 수 있다.

     

    (function() {
    
    })();

    즉시실행함수는 위와 같이 생겼다.

    함수에 ()를 씌워서 전역변수를 외부로부터 보호하고 그 뒤에 다시 ()를 붙여서 함수를 즉시 실행한다.

     

     

    (function() {
        var color = 'blue';
    
        console.log('I like ' + color);
    
        setTimeout(function() {
            console.log('I like ' + color);
        }, 1000);
    })();
    
    var color = 'red';
    
    console.log('I like ' + color);
    
    setTimeout(function() {
        console.log('I like ' + color);
    }, 1000);

    이제 아까 만들었던 예제 코드 중 변수 blue가 있는 부분을 즉시실행함수로 바꾼 후 결과를 출력하면 다음과 같이 출력된다.

     

     

    즉시실행함수안에 선언된 color는 함수 scope에 종속된 지역변수가 되기 때문에

    아래의 전역 변수 color의 영향을 받지 않고 'blue'라는 값을 유지하게 된다.

    반응형

    COMMENT