[Web]자바스크립트 스코프와 클로저 호이스팅

2 minute read

스코프, 클로저, 호이스팅

스코프와 클로저 호이스팅은 자바스크립트에서 중요한 개념이다. 자바스크립트 개발하는데 위 개념을 몰라도 크게 상관없지만 프로젝트 크기가 커지고 개발의 범위가 넓어지면 변수참조에 대해 어려움을 겪기때문에 반드시 알아야하는 개념중 하나이다.

스코프

스코프는 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이다.

스코프는 식별자의 유효범위이다.

전역스코프

전역 스코프는 변수가 함수 바깥이나 {}바깥에서 선언되어 있는 것을 뜻한다.

var globalvalue = 'test';
function test(){
	console.log(globalvalue); //test
};

console.log(globalvalue); 	//test

함수 레벨 스코프 / 블록 레벨 스코프

자바스크립트는 초기에는 함수 레벨 스코프(function-level scope)를 따른다. 하지만 자바스크립트(ES6)는 함수 레벨과 블록 레벨의 렉시컬 스코프규칙을 따른다. (let, const)

함수 레벨 스코프

함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다.

var a = 10;     // 전역변수

(function () {
  var b = 20;   // 지역변수
})();

console.log(a); // 10
console.log(b); // "b" is not defined

자바스크립트는 기본적으로 함수레벨스코프를 따른다.

블록 레벨 스코프

최소 권한 노출의 원칙을 확장하여 정보를 함수 안에 숨기고 나아가 정보를 코드 블록안에 숨기기 위한 도구다.
우리가 변수를 {} 괄호 안에 const나 let키워드로 선언했을 때, 우리는 {}괄호 안에서만 이 변수에 접근할 수 있다. (ES6에서 새롭게 등장)

{
    const hello = 'Hello CSS-Tricks Reader!'
    console.log(hello) // 'Hello CSS-Tricks Reader!'
}

console.log(hello) // Error, hello is not defined

렉시컬 스코프

함수의 상위 스코프를 결정하는데에는 두 가지 방법이 있다. 첫 번째 방법은 동적 스코프로 함수가 어디서 호출했는지에 따라 상위 스코프를 결정하고, 두 번째 방법은 렉시컬 스코프로 함수가 어디에서 호출되어있는지가 아니라 함수가 어디서 선언되었는지에 따라 상위 스코프를 결정한다.

아래 코드를 보자.

var x = 1;

function foo() {
  var x = 10;
  bar();
}

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

foo(); // 1
bar(); // 1

위 예제의 함수 bar는 전역에 선언되었다. 따라서 함수 bar의 상위 스코프는 전역 스코프이고 위 예제는 전역 변수 x의 값 1을 두번 출력한다.

클로저

클로저는 독립적인 (자유) 변수를 가리키는 함수이다. 또는, 클로저 안에 정의된 함수는 만들어진 환경을 ‘기억한다’. 클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수

function outerFunc() {
  var x = 10;
  var innerFunc = function () { console.log(x); };
  innerFunc();
}

outerFunc(); // 10
/**
 *  함수 outerFunc를 호출하면 내부 함수 innerFunc가 반환된다.
 *  그리고 함수 outerFunc의 실행 컨텍스트는 소멸한다.
 */
var inner = outerFunc();
inner(); // 10

호이스팅

함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다. 아래 코드를 보자.

// 변수 호이스팅
console.log(hoisting); //undefined
var hoisting = "success";
console.log(hoisting); // 'success'
//함수 호이스팅
a();
function a() {
  console.log("a is not a function");
};
  • var 변수 선언과 함수선언문에서만 호이스팅이 일어난다.
  • var 변수/함수의 선언만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.
  • let/const 변수 선언과 함수표현식에서는 호이스팅이 발생하지 않는다.

참조

스코프 JavaScript 클로저(Closure) JavaScript 호이스팅(Hoisting)이란