Language/Javascript

Javascript - 실행 컨텍스트와 스코프, 클로저

둉이 2021. 12. 1. 00:18

 

실행 컨텍스트란?

  • 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
  • 동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성 → 해당 실행 컨텍스트를 콜 스택에 저장 → 선입후출(stack)로 코드들을 실행하여 전체 코드의 환경과 순서 보장
  • 예시
    /* 여기는 전역 컨텍스트입니다. */
    var a = 1;
    function outer() {
    	/* 여기는 outer 함수의 컨텍스트입니다. */
    	function inner() {
    		/* 여기는 inner 함수의 컨텍스트입니다. */
    		console.log(a);// undefined 출력var a = 3;
    	}
    	inner();
    	console.log(a);// 1 출력
    }
    outer();
    console.log(a);// 1 출력
    : 차례대로 전역 컨텍스트 push -> outer push  -> inner push  -> inner pop -> outer pop -> 전역 컨텍스트 pop
  • 실행 컨텍스트에 포함되는 정보들은 다음과 같음
    • VariableEnvironment
      • 현재 컨텍스트의 식별자 정보 + 외부 환경 정보 (= 선언 시점의 LexicalEnvironment)
      • 스냅샷 개념으로 변경 사항이 반영되지는 않음
    • LexicalEnvironment(=정적 환경)
      • 변경 사항이 실시간으로 반영되는 실행 환경
    • ThisBinding
      • this 식별자에 바인딩 되는 대상 객체

 

스코프(scope)란?

  • 변수(식별자)에 대한 유효 범위
  • 자바스크립트는 전역 공간을 제외하고 오직 함수에 의해서만 스코프가 생성됨
  • 스코프 체인(scope chain)
    • 스코프를 안에서부터 바깥으로 차례대로 검색해 나가는 것
    • 변수 은닉화(variable shadowing) : 여러 스코프에서 동일한 식별자를 선언한 경우에는 무조건 스코프 체인 상에서 가장 먼저 발견된(가장 가까운) 식별자에만 접근 가능
/* 여기는 전역 컨텍스트입니다. */
var a = 1;
function outer() {
	/* 여기는 outer 함수의 컨텍스트입니다. */
	function inner() {
		/* 여기는 inner 함수의 컨텍스트입니다. */
		console.log(a);// undefined 출력var a = 3;
	}
	inner();
	console.log(a);// 1 출력
}
outer();
console.log(a);// 1 출력

// → outer 함수에서는 outer 함수 스코프와 전역 스코프에 접근이 가능하지만, inner 스코프에는 접근이 불가능
// → inner 함수에서는 outer 함수 스코프와 전역 스코프에 모두 접근 가능

 

함수의 상위 스코프를 결정하는 방법

  • 동적 스코프
    • 함수가 어디서 호출되었는지에 따라 상위 스코프를 결정
  • 정적 스코프(=렉시컬 스코프)
    • 함수가 어디에 선언되었는지에 따라 상위 스코프를 결정
    • 자바스크립트는 함수를 선언함으로써 스코프를 생성하므로 렉시컬 스코프에 따라 상위 스코프를 결정함

 

클로저란?

  • 어떠한 함수를 렉시컬 스코프 밖에서 실행해도 원래 선언되었던 렉시컬 스코프를 기억하고 접근할 수 있도록 하는 특성
var color = 'red';
function foo() {
    var color = 'blue'; // 2
    function bar() {
        console.log(color); // 1
    }
    return bar;
}
var baz = foo(); // 3
baz(); // 4

 

→ bar()는 자신이 생성된 렉시컬 스코프에서 벗어나 바깥 스코프에 위치한 baz라는 새로운 변수에 할당되어 실행이 됐는데도 정상적으로 작동이 되고 있음

 

자바스크립트의 스코프(렉시컬 스코프)는 해당 코드가 작성된 문맥에서 바로 결정되기 때문에 GC에서 회수되지 않고 렉시컬 스코프를 유지할 수 있는 것임

 

  • 대표적인 클로저 예시
function count() {
    let i;
    for (i = 1; i < 10; i += 1) {
        setTimeout(function timer() {
            console.log(i);  // 9번의 10 출력
        }, i*100);
    }
}
count();

 

  • 클로저 활용
    • 함수 은닉화