bdfgdfg

자바스크립트의 스코프 레벨,스코프 체인,클로져 본문

웹프로그래밍/HTML_CSS_Javascript 기초

자바스크립트의 스코프 레벨,스코프 체인,클로져

marmelo12 2023. 9. 12. 23:13
반응형

우선 클로져 개념을 이해하기전에 자바스크립트의 Scope와 Scope Chain을 먼저 이해하는게 좋다.
 -> Scope는 변수의 접근 범위. 즉 식별자의 유효 범위를 의미한다. 
 
C,JAVA와 같은 컴파일 언어에서는 블록레벨 Scope를 따른다.
다만 js(다른 언어는 모르겠음.)의 경우 함수레벨 Scope를 따른다.
 
둘의 차이는 밑과 같이

// 블록레벨 SCOPE라면.
{
    var x = 10;
}
// 에러가 떠야한다.
// 다만 JS에서는 함수레벨 Scope를 가지므로 밑은 10이 출력이 된다.
console.log(x);

블록레벨 Scope였다면 x라는 지역변수에는 접근할 수 없어 에러가 발생하지만
js에는 정상적으로 10이 출력이 된다.
 
여기서 중요한건 Scope의 범위. JS는 함수레벨의 Scope를 가진다고 했다. 그럼 외부함수에 중첩된 inner함수가 있고,
외부함수의 변수를 inner함수에서 접근할 수 있다는 말이 된다.
 
이렇게 설명하면 와닿지 않는데, 실제 블록레벨 Scope를 생각해보면 간단하다.

에러가 발생하지않고 50이 정상적으로 잘 출력되는 모습. 그렇다면 JS의 중첩 함수에서 외부함수의 식별자에 접근해보면?

function outerFunc() {
    var x = 10;
    function innerFunc() {
        x = 50;
        console.log(x);
    }

    innerFunc();
}
outerFunc();

50이 정상적으로 출력이 된다. 이 말은 즉슨 외부함수(outerFunc)의 식별자 x에 정상적인 접근이 가능했다는 의미다.
 
그럼 위 지식을 기반으로 밑의 코드는 어떻게 출력될지 고민해보자.

https://www.youtube.com/watch?v=PVYjfrgZhtU

순서대로 밑과 같이 출력된다.

나는 전역 x야. -> 함수레벨 Scope
나는 outer함수의 지역 y야

나는 inner함수의 지역 x야
나는 outer함수의 지역 y야

나는 전역 x야
y는 접근불가능
 
자바스크립트에서는 스코프를 inner지역 스코프 -> outer지역 스코프 -> 전역 스코프 순으로 식별자를 찾게된다.
즉 가장 가까운 함수부터 외부(부모 함수)까지 순서대로 식별하러간다는 의미.
 -> 이렇게 하위에서 상위로 올라가는 스코프 체인의 특성이 있음을 알고있어야한다.(렉시컬 스코프. 함수 선언 기준으로 상위 스코프가 결정.(즉 상위 스코프가 함수의 호출순서가아님)
 -> 참고로 자바스크립트도 당연히 main함수가 존재한다. script가 시작된 공간이 main함수 영역.
  --> 그렇기에 위 예제에서 전역 스코프 var x를 함수(상위)가 아님에도 접근할 수 있는 것.
 

블록 레벨을 가지는 타입의 let, const

자바스크립트의 ES6버전 이후로는 블록레벨 스코프를 가진 let과 const키워드가 나왔다.
즉 전역(Main영역의 함수레벨이라고 보자)과 함수레벨 Scope를 가진 var와 다르게 블록단위의 Scope를 가진다는 의미.

위 예제에서 var의 변수 a는 testFunc에서 접근이 가능하다. 전역단위 Scope를 가지므로.
반대로 let과 const의 경우.

위 코드에서는 오류가 발생한다. let과 const는 block단위의 scope를 가지므로 해당 변수에 접근할 수 없기 때문.
즉. 스코프 체인을 따르면 testFunc의 a,b 식별자를 찾는데 상위 Scope를 뒤져봐도 해당 변수들은 존재하지 않기때문에 찾지 못하는 것. (let과 const는 해당 블록에서만 유효했기에 찾을 수 없다)
 
하지만! 상위 스코프에서 유효하기만 한다면 해당 식별자에 접근할 수는 있다는것을 잊으면 안된다.

a,b는 전역에서 유효했기 때문에, 접근이 가능은 하다는 것.
 -> 이전에는 a,b가 블록에서만 생성되고 사라졌음.
 
정리하면.
자바스크립트에서 Scope는 우선 스코프체인을 따라 찾고자 하는 식별자를 우선해서 찾게 되며.
var, let 과 const와 같이. var의 경우 함수레벨 Scope를 가지기에 상위(부모 함수) Scope에 존재하기만 한다면 식별할 수 있지만, 블록레벨에서 유효한 범위가 종료된 let과 const는 상위 Scope에 존재하더라도 식별할 수 없다.
 
var,let,const는 해당 키워드를 사용한 변수(식별자)의 살아있는 범위.
스코프 체인은 변수(식별자)의 하위~상위함수로 차례로 식별자를 탐색하는 과정.
이라고 구분해서 생각하면 편할듯.
 

클로져

클로저 함수는 이미 종료된 함수가 반환한 함수를 클로저 함수라고 한다.
이미 종료된 함수의 지역변수등. 자신이 선언되었을 당시 환경인 Scope를 기억하는것이 클로져.
 -> 따로 메모리에 저장하게 되며, 만약 더이상 필요하지 않게 된다면 해당 클로저 함수에 null을 대입하여 닫아줘야한다.
 

<script>
    
    function func(){
        let cnt = 0;
        return function() {
            return ++cnt;
        }
    }


    const funt = func();

    console.log(funt()); // cnt == 1
    console.log(funt()); // cnt == 2
    console.log(funt()); // cnt == 3

</script>

 
참고 자료
https://www.youtube.com/watch?v=PVYjfrgZhtU
 

반응형
Comments