대가는 결과를 만든다

스코프, 호이스팅, 클로저 정리하기 본문

개발/Javascript

스코프, 호이스팅, 클로저 정리하기

yunzema 2020. 4. 4. 18:12
반응형

1. 스코프란?

  - scope란 사전적 의미로 '범위'라는 의미를 지닌다.

  - 자바스크립트에서 변수에 접근할 수 있는 범위 혹은 변수가 영향을 끼칠 수 있는 범위라고 생각하면 된다.

  - 크게 나누면 전역, 지역 스코프로 나눌 수 있지만 스코프 레벨을 좀더 자세하게 나누자면, 함수 레벨 스코프, 블록 레벨 스코프(ES6), 렉시컬 스코프로 나눌 수 있다.

 

1-1. 함수레벨 스코프

  - 자바스크립트에서 var 키워드로 선언된 변수, 함수 선언식으로 만들어진 함수는 함수 레벨 스코프를 지닌다.

  - 변수는 함수 내부 전체에서(만) 유효한 식별자가 된다.

 

1-2. 블록 레벨 스코프

  - ES6의 let, const 키워드는 블록레벨 스코프 변수를 만들어 준다.

  - 여기서 블록이란 if/else, while/for 내부로 정해지는 범위를 말한다.

  - ES6에서 let, const가 도입되면서 var는 사용하지 않는다. let으로 대체가 가능하고, var는 함수 전체에 대한 스코프를 가지므로, 혼란을 야기할 수 있다.

 

1-3. 렉시컬 스코프

  - 호출스택과 관계없이 각각의 소스코드가 작성된 그 문맥을 기준으로 데이터를 대응하고, 그 대응이 런타임에서 변하지 않는다. 

  * this는 제외

var x = 'global';

funtion foo(){
 var x = 'local';
 bar();
}

function bar(){
  console.log(x);
}

foo();	//global 출력
bar();	//global 출력

 

2. 호이스팅

  - 호이스팅은 사전적 의미로 '끌어올림' 이라는 의미를 지닌다.

  - 자바스크립트 엔진은 코드를 컴파일-> 인터프리팅의 순으로 처리하는데,

    컴파일 단계에서 var a = 2; 라는 코드를 두개의 구문으로 분리하여 본다.

     => var a;  //변수 선언 단계

     => a=2;   //변수 초기화 단계

  - 선언 단계에서는 그 선언이 코드에서 어디에 위치하든 해당 스코프의 컴파일 단계에서 처리한다.

  - 따라서 선언 단계가 스코프의 꼭대기로 끌어올려지는 것을 호이스팅이라고 한다.

  - 하지만 해당 값을 선언하기도 전에 참조 가능한 것이랑 햇갈리면 안된다.

//선언부가 호이스팅되므로 2를 정상적으로 출력하는 함수
function foo() {
  a=2;
  var a=2;
  console.log(a);
}

//선언 전 참조되는 경우에는 undefined를 반환
function foo(){
  console.log(a);
  var a=2;
}

  * 블록 스코프인 ES6의 let도 호이스팅 되지만, 선언 전에 참조할 경우 undefied를 반환하지 않고 ReferenceError를 발생시킨다.

 

3. 클로저

  - (Closure)클로저는 사전적인 의미로 '포섭'

  - 클로저 = 함수 + 함수를 둘러싼 환경(렉시컬 환경)

  - 자바스크립트에서 클로저는 함수가 생성되는 시점에 생성

    즉, 함수가 생성될 때 그 함수의 렉시컬 환경을 포섭하여, 실행될 때 함께 이용된다.

 

개념적으로는 이해가 되는 것 같다. 그러면 코드로 클로저와 클로저가 아닌 것을 구별해보자.

아래 두 예제는 모두 blue를 출력하지만, 첫번째는 클로저의 예시가 아니고, 두번째는 클로저의 예시다.

 

클로저가 아닌 예시 : bar()는 foo안에서 실행되었지 foo밖에서 실행되는 것이 아니므로 정확히 클로저의 예라고 볼 수 없다.

function foo(){
	var color = 'blue';
    
    	//foo 스코프를 외부 렉시컬 환경으로 참조하여 저장한다.
	function bar(){
    	console.log(color);		//foo의 color 값인 'blue'를 참조한다.
    }
    bar();
}

foo();	//blue를 출력

클로저 예시 : bar()s는 자신이 생성한 렉시컬 스코프를 벗어나 호출되었고, 현재 실행 스택과 관련 없는 foo를 거쳐 color 값을 참조했다. bar()와 같은 함수를 클로저라고 한다.

var color = 'red';
function foo(){
    var color = 'blue';
    
    //bar는 외부 렉시컬 환경 참조로 foo의 color를 저장
    function bar(){
  		console.log(color)
    }
    
    return bar;
}

var baz = foo();	//foo가 반환한 bar() 함수는 baz로 재명명된다.
baz();			//blue를 출력
//bar는 자신의 스코프에서 color를 먼저 찾고, 그다음 외부 렉시컬 환경을 참조해서 color를 찾는다.

 

참고 : https://meetup.toast.com/posts/86

 

자바스크립트의 스코프와 클로저 : TOAST Meetup

자바스크립트의 스코프와 클로저

meetup.toast.com

 

Comments