본문 바로가기
개발/자바스크립트

[자바스크립트] scope chain 과 variable shadowing에 대해

by 핸디(Handy) 2020. 11. 11.

이번 포스트에서는 자바스크립트가 가지고 있는 딥한 특징 variable shadowing(변수 가려짐?)에 대해 알아보겠습니다.

위키피디아의 문서를 보면 아래와 같이 언급되어있습니다.

In computer programming, variable shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope. At the level of identifiers (names, rather than variables), this is known as name masking. This outer variable is said to be shadowed by the inner variable, while the inner identifier is said to mask the outer identifier. This can lead to confusion, as it may be unclear which variable subsequent uses of the shadowed variable name refer to, which depends on the name resolution rules of the language.

ECMAScript 6 introduction of `let` and `const` with block scoping allow variable shadowing.

https://en.wikipedia.org/wiki/Variable_shadowing

요약해보자면

1.variable shadowing은 same name를 가진 변수가 외부 scope에도 선언된 것이다.
2.name masking 으로도 불린다.
3.이것은 혼란을 유발한다.
4.ECMAScript 6는 variable shadowing를 let, const로 허용했다. 정도입니다.


역시 글로는 단박에 이해하기가 어렵습니다. 허허

우선 variable shadowing를 알아보기 전에 자바스크립트의 Scope chain에 대해 알고 있어야 합니다.

자바스크립트의 interpreter는 항상 그 함수의 지역 변수를 먼저 찾고 없으면 한 scope 씩 거슬러 올라가며 해당 변수를 찾아갑니다.

좀 더 딥하게 말하자면,

우리가 어떤 변수를 사용하고자 할 때, 자바스크립트 엔진은 호출된 함수의 자식 함수의 지역변수(local scope)를 가장 먼저 찾았습니다. 만약 해당 scope에 값이 있으면 가져다 쓰고 없으면 한 단계 위로 올라가고 찾을 때까지 바깥 범위로 확장합니다.

그렇다면 undefined는 무엇이냐?  바로 global scope(window)까지 갔는데도 못 찾는 경우입니다. 이때 값이 undefined 되는 것입니다. 

이렇게 지역변수부터 글로벌까지 찾아가는 것을 Scope Chain이라고 합니다.


여기서 이제 질문이 생깁니다.

만약 scope chain에서 중복된 이름을 가진 변수는 어떻게 처리될까?

function myFunc() {
    let my_var = 'test';
    if (true) {
        let my_var = 'new test';
        console.log(my_var); // new test
    }
    console.log(my_var); // test
}
myFunc();

보시다시피 자바스크립트에서는 아무런 에러 없이 잘 동작합니다.

if 안에 있는 console.log는 if문 scope 안에 있는 my_var = 'new test';를 출력하고 

그다음으로 myFunc scope에 있는 test를 출력한 것입니다.

따라서 variable shadowing의 경우, 

같은 이름을 가진 모든 지역 변수는 바깥 scope의 변수에 비해 항상 높은 우선순위를 가진다는 사실을 확인할 수 있었습니다.

다만 이런 기능이 있다는 것을 알고는 있지만 실사용은 지양할듯합니다.

위에서도 언급되었다시피 confusion를 일으킬 여지가 너무 다분합니다. 다만 우리가 일반적으로 쓰는 아래와 같은 상황에서는 이젠 고민 없이 쓸 수가 있겠습니다.

function myFunc() {
    for(let i =0; i< 10; i++){
        //do something first
    }
    if (true) {
    	for(let i =5; i< 20; i++){
        //do something second
        }
    }
}
myFunc();

 

 

 

댓글