Small Grey Outline Pointer [인간JS되기] 스코프 체인
본문 바로가기
Dev./JavaScript

[인간JS되기] 스코프 체인

by sso. 2023. 3. 6.

제로초님 강의 보고 정리 중
[인간 JS 엔진 되기 1-4]
 
 
 

스코프 체인

정의: 식별자의 유효 범위 일종의 리스트로서 전역 객체와 중첩된 함수의 스코프의 레퍼런스를 차례로 저장하고, 
의미 그대로 각각의 스코프가 어떻게 연결(chain)되고 있는지 보여주는 것
 
스코프 체인을 간단히 설명하면 '함수에서 어떤 값에 접근이 가능한가 불가능한가'
 
ES2015 기준으로 그 이전까지는 함수가 기준이었지만, 그 후로는 { } 블록이 기준이 되었다
 
함수가 아닌 블록들 
if() {}
for() {}
while() {} 
등등....
 
그 외에도 { } 그냥 이렇게만 있는 블록도 있는데 객체가 아니므로 주의!
=> 이걸 객체로 만들고 싶으면 ({ }) 이렇게 소괄호로 감싸서 사용
 
 

//객체를 리턴하는 함수가 아니라, 블럭이다 
const a = () => {}

//위의 코드를 객체로 만들려면 
const a = () => ({})

 
 


const x = 'x';
function c(){
    const y = 'y';
    console.log('c');
    function b(){
        const z = 'z';
        console.log('b');
        c();
    }
}

function a(){
    const x = 'x';
    console.log('a');
    b();
}

a();
c();

지난 시간에는 함수를 호출하면 실행부로 간다고 배웠지만, 
무조건 호출한다고 해서 실행부로 이동할 수 있는 것은 아니다
그렇다면 이것을 판단할 수 있는 기준은 무엇일까?? 스코프체인이다 
 
지난 번에 했던 예제 코드에서 함수b의 위치를 수정하고 b함수를 실행했을 때를 살펴보자
 

 
에러가 뜬다
 
함수 b를 선언했는데 왜 안되는걸까?
스코프(스코프체인)을 모르면 이런 일이 일어난다
함수를 호출한다고 해서 바로 실행부로 순간이동을 하는 것이 아니라 안되는 경우도 존재한다는 것을 알고 있어야 한다!
 
판단을 어떻게 할까?
호출과 선언을 정확히 알고 있어야 이해할 수 있다
호출 스택을 머릿속에 그렸던 것처럼 그림을 하나 더 그려서 생각해본다
 
함수 선언을 기준으로 콜스택을 그려본다
 
 
 

 
 
코딩할 때 들여쓰기 잘하면 좋다
호출스택은 호출만 쌓이는 것이고, 스코프체인은 선언에만 해당. 호출부분은 아무 영향 없음!
 
 
선언이라는 것은 한번 작성해놓으면 바뀌지 않고 실행을 시켜도 코드는 바뀌지 않는다, 고정
=> 렉시컬 스코프
 


 
스코프체인 분석하는 법 => 함수의 선언들만 보면 된다!
내 부모 함수가 누군지 파악해서 anonymous 까지 가보자!
 
어떤 함수에서 어떤 변수에 접근이 가능한가 못하는가를 파악하려면

const x = 'x';
function c(){
    const y = 'y';
    console.log('c');
    function b(){
        const z = 'z';
        console.log('b');
        c();
    }
}

function a(){
    const x = 'x';
    console.log('a');
    b(); //호출
}

a();
c();

 
Q. a 함수에서 b에 접근이 가능한가?
-> a기준으로 b 선언을 찾아본다
 

 
호출만 있고 선언은 없음 그렇다면 anonymous에서 찾아본다
 
 

접어놓고 찾아봐도 b 선언은 없다 => a함수에서  b함수에 접근할 수 없음
이것이 b is not defined 에러가 나는 이유이다
 
 
그렇다면 반대로 b에서 a 접근이 가능한가?
b->c->anonymous 이렇게 가상의 화살표(스코프체인)를 그리면서 따라가본다
b의 부모가 c이고, c를 따라가면 anonymous가 나온다
 
1) b안에서 a를 찾는다 // 없음
2) c안에서 a를 찾는다 // 없음
3) anonymous 에서 a를 찾는다 // 있음
 
b에서 a에 접근할 수 있다
 
 
이 때 헷갈릴 수 있는 점 anonymous에서의 선언을 찾을 때는 선언부를 다 접어놓고 그 때 남은 것만 anonymous영역에서 찾는걸로 해야 함.  코드를 다 펼쳐놓고 a에서 b를 접근할 수 있냐고 생각하면 접근할 수 있다고 생각할 수도 있다
 
선언에 대한 전체적인 지도를 그려본다
 
anonymous 안에서 선언 된 것들만 모아놓기
anony -> x, c, a
c함수 안에서 선언된 것들만 모아놓기 
c -> y, b
b함수 안에서 선언된 것들만 모아놓기 
b-> z
a함수 안에서 선언된 것들만 모아놓기 
a-> x
 
그렇다면 위의 지도를 머릿속에 그려놓고
Q. a에서 b에 접근할 수 있는가?
a 의 부모-> anonymous
a-> x // a에서 b 접근 불가
anony -> x, c, a // anonymous에서 b 접근 불가
 
 


 
 

const x = 'x1';
function c(){
    const y = 'y';
    console.log('c');
    function b(){
        const z = 'z';
        console.log('b');
        c();
    }
}

function a(){
    const x = 'x2';
    console.log('a');
    b();
    console.log(x); //이 때 x의 값은?
}

a();
c();

같은 변수인데, 변수 이름만 같고 스코프는 서로 다르고(위치가 다르고), 값도 다르다
 
 
 
둘중에 누구를 택하냐 (아까 위에서 그린 지도를 생각한다)
a를 먼저 보고 나서 anonymous를 찾는다
그렇다면 a에도 x가 있기 때문에 목적 달성이므로 anony까지 가지 않아도 됨
따라서 이때 x는 x2가 나온다
 
 

728x90

댓글