티스토리 뷰

안녕하세요 좋아요요정입니다. 

오늘은 "스코프"에 대해 설명해보려 합니다.

스코프는 변수와 함수, 객체들의 생명주기와 접근성 등을 결정하는 아주 중요한 개념입니다.

유효 범위로써 변수와 매개변수가 어디까지 유효한지 나타냅니다. 

 

저는 전역 스코프, 지역 스코프, 전역에서 선언된 변수는 지역에서 접근이 가능하지만, 지역에서 선언된 변수는 전역에서 접근이 불가능하다라는 정의를 통해 이해하고 있었습니다.

콜 스택과 실행 컨텍스트, 스코프, 스코프체인 정의도 알고 개념도 아는데 머릿속에는 두리뭉실하게 인식하고 있었습니다. 

오늘은 콜 스택과 실행 컨텍스트, 스코프, 스코프체인을 제대로 잡고 스코프에 대해 다시 한번 정의해보겠습니다.

 

 

 


콜스택

콜 스택(Call Stack)은 메모리 상에 함수의 호출과 연관되는 데이터가 저장되는 영역입니다. 함수를 호출하게 되면 스택 영역에 할당이 되고 호출이 되면 끝나고 소멸이 되죠. 자바스크립트는 단일 스레드 프로그래밍 언어이므로 단일 콜 스택이 있습니다. 한번에 하나의 일만 처리할 수 있습니다. 코드 내에 함수는 여러개인데 어떻게 하나의 일만 처리할 수 있을까요?

호출 스택의 예를 먼저 보겠습니다.

 

const fish = '바다물고기';

function ship() {
	console.log('현재 위치는  ship()', fish,'를 잡았다!');
    const cat = '해적 고양이';
    
    function flyShip() {
    	console.log('현재 위치는  flyShip()', fish, '를 잡았다!');
    	console.log('현재 위치는  flyShip()', cat, '를 잡았다!');
    	const cat2 = '하늘 고양이';
    }
    flyShip()
}
ship()

이 코드가 실행이 되면 콜스택에서는 어떤 일이 일어날까요? 

아래 그림의 순서대로 함수의 실행 컨텍스트가 쌓이고, 제거되게 됩니다.

1. 코드가 실행되면 전역 실행 컨텍스트가 생성됩니다. 

2. 그 다음 ship함수가 실행이 되면  ship실행 컨텍스트가 콜스택에 쌓이게 됩니다.

3. ship함수 내의 flyShip가 실행이 되면 ship실행 컨텍스트의 위로 쌓이게 됩니다.

4. flyShip함수가 종료되면 flyShip실행 컨텍스트가 제거됩니다.

5. ship함수가 종료되면 ship실행 컨텍스트가 제거됩니다.

 

코드가 종료되면 전역 실행 컨텍스트가 제거됩니다.

콜 스택에 실행되는 함수를 위한 스택이 쌓이게 되고, 함수가 종료되면 제거되는 순서를 가지고 있습니다.

 

 

 

이 때 자바스크립트 엔진은 최상단에 위치한(가장 마지막에 생성된 실행 컨텍스트)를 진행하고 있습니다.

함수 내부를 진행하고 코드가 완료되면, 실행 컨텍스트가 제거되고 이전(호출된 후) 코드를 마저 진행하게 됩니다.

 

 

 

 

 

실행 컨텍스트

그렇다면 실행 컨텍스트에서는 어떤 일을 할까요?

실행 컨텍스트(Execution Context)는 렉시컬 환경과 변수 환경,  This binding으로 이루어져 있습니다. 

함수가 호출되면 힙주소에서 함수를 가지고 옵니다. 실행 컨텍스트에서는 현재 실행중이 코드 블록에서 코드들을 한줄씩 읽고, 선언한 변수들을 등록하고 관리하는 작업을 합니다. 그리고 외부 렉시컬 환경을 기록하고 있죠. 

 

LexicalEnvironment: {
	envrionmentRecord: {
    		지역변수, 매개변수 등 보관
    },
    outerLexicalEnvrionment: 현재 코드가 실행중인 렉시컬 스코프에 대한 참조
}

실행 컨텍스트에서는 코드를 실행하는 쓰레드와 로컬 메모리 영역(지역변수, 매개변수 등이 보관됨), 렉시컬 스코프를 참조할 수 있도록  기록되어지는 공간이 있습니다. 

 

콜스택영역에서 함수가 호출되면 실행 컨텍스트가 쌓인다.라고 했었죠, 이전 코드를 예로 다시 실행 컨텍스트를 그려보겠습니다.

 

여기에서 중요한 외부 렉시컬 환경을 기록 <- 렉시컬 스코프 이해의 시작이 됩니다.

 

 

 

 

스코프

사랑하는 MDN의 설명을 먼저 보시겠습니다.

 

저는 여기 번역된 현재 실행되는 컨텍스트를 뜻한다는 의미에서 헷깔렸습니다. 다른 블로그들을 찾아봐도 스택, 실행 컨텍스트를 혼용해서 사용하다보니 더욱 헷깔렸죠.

스코프는 값과 표현식이 표현되거나 참조 될 수 있음을 의미, 

"해당 스코프 내에 있지 않다면 사용할 수 없다." ,  "하위 스코프는 상위 스코프에 접근할 수 있지만 반대는 불가하다."

 

 

이미지와 함께 다시 설명해보겠습니다.

 

콜 스택에 쌓인 실행 컨텍스트는 최상단이 현재 실행되고 있는 컨텍스트입니다.

현재 3개의 실행 컨텍스트가 쌓여있죠? 최상단에 쌓인 flyShip()의 코드가 실행되고 있습니다.

 

이때 flyShip()에서 fish를 찾는다면 어떻게 될까요? 

1. 먼저 현재 실행하고 있는 컨텍스트의 메모리에서 변수 fish를 찾습니다.

2. 찾지 못하면 렉시컬 스코프를 참조해(그림으로 닻으로 표현) ship 실행 컨텍스트로 이동해 찾습니다.

3. ship 실행 컨텍스트에서 찾지 못한다면 렉시컬 스코프를 참조해 전역 실행 컨텍스트로 이동해 찾습니다. 

4. 변수를 발견하면 값을 가지고 코드를 마저 실행합니다.

 

 

이 때 스코프는 현재 실행중이 실행컨텐스트를 기준으로 행동합니다.

 

만약 ship()에서  cat2 하늘고양이를 찾는다면 어떻게 될까요? 

닻을 타고 올라갈 수 없습니다.  ship컨텍스트에는 상단으로 가는 지도, 길이 없습니다. 하위로 찾아갈 수 있습니다. 

예 해적고양이는 하늘고양이 영역에 갈 수 없습니다(입체적으로 이해해보기..)

 

 

이 스코프는 함수가 호출된 실행 컨텍스트로 찾아가는 닻(링크)라고 생각하시면 좋습니다.

 

 

 

 

스코프 체이닝

그리고 이렇게 닻(렉시컬 스코프)들이 계층적으로 연결되어있걸 스코프 체이닝이라고 합니다.

 

 

 

 


왜? 에 대해서 많은 것을 생각해보는 시간이 되었습니다.

함수 내에서 선언한 변수를 전역 영역에서 사용할 수 없다는 것은 알고 있었습니다. 네 예러가 뜨니까요..

그런데 왜? 왜 에러가 나는지, 자바스크립트에서는 이 모든걸 메모리에 모두 저장하고 있지 않은 것인지, 어떻게 저장하고 어떻게 제거가 되는지에 대해 구체적으로 이미지화 시켜보는 시간이 되었습니다.

자바스크립트 만든 사람처럼 천재가 되고싶네요. 멋있습니다..

 

이해가 안가는 부분(스택과 실행 컨텍스트가 다른 줄 알고 있었음)을 설명해주신 hoon님 감사합니다 ..

오늘도 열심히 자바스크립트 스터디! 다음 세션도 기대가 됩니다. :) 감사합니다 

아 맞다 새해 복 많이 받으세요! 그리고 행복한 코딩라이프되세요~! 

 

잘못된 이해가 있다면 자비로운 댓글 부탁드립니다. 감사합니다!

JavaScript 스터디 팀 러버덕과 함께 합니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함