img
스코프, 호이스팅, 클로저에 대해 알아보자2023.09.07면접/CS

스코프 (Scope)

스코프란 쉽게 설명하자면 변수의 접근범위 라고 할 수 있다. 자바스크립트에는 전역(global)지역(local) 두 가지의 스코프가 있다. 지역 스코프는 해당 지역에서만 접근이 가능하고, 전역 스코프는 말 그대로 전역에서 접근이 가능하다.

자바스크립트에서 함수를 생성하면 새로운 스코프를 생성하게 된다. 그러므로 함수 몸체에 선언한 변수는 함수 안에서만 사용할 수 있는데, 이걸 함수 스코프(function-scoped) 라고 한다. -> 함수 스코프는 지역 스코프의 대표적인 예

쉬운 이해를 위해서 아래의 코드를 보자

function exampleFunction() { // 지역(함수) 스코프
  var x = "declared inside function";
  // x는 오직 exampleFunction 내부에서만 사용 가능.
  console.log(x); // "declared inside function" 출력
}

console.log(x); // 에러 발생

이 코드에서 x 는 지역 스코프가 된다. 함수 몸체에서 선언한 변수는 함수 안에서만 사용할 수 있기 때문에 console.log(x) 는 에러가 발생한다.

다른 코드를 통해 다른 예제를 알아보자

var x = "declared outside function"; // 전역 스코프

exampleFunction();

function exampleFunction() {
  console.log(x); // "declared outside function" 출력
}

console.log(x); // "declared outside function" 출력

x 는 전역에 선언된 변수로 전역 스코프를 갖는다. 그렇기 때문에 exampleFunction 에서도 접근이 가능하고, console.log(x) 에서도 접근이 가능하다.

그렇다면 이런 경우에서는 어떻게 동작할까?

var x = "declared outside function"; // 전역 스코프

exampleFunction();

function exampleFunction() { // 지역(함수) 스코프
  var x = "declared inside function"
  console.log(x); // "declared inside function" 출력
}

console.log(x); // "declared outside function" 출력

이 코드는 전역에 선언된 x 와 지역에 선언된 x 가 동시에 존재하는 경우이다. exampleFunction 에서는 declared inside function 을 출력하고 전역에서는 declared outside function 을 출력한다.

이는 Scope Chain 때문에 일어나는 현상인데, 자신의 스코프 내에 변수가 없으면 Scope Chain 을 통해 상위 스코프에 존재하는 변수를 찾아나가기 때문에 일어나는 현상이다.

또한 블록 스코프(block scope) 도 존재하는데, 자바스크립트 ES6부터 let, const 로 변수 선언이 가능해지면서 일반 블록에서도 스코프를 생성할 수 있게 되었다.

호이스팅(Hoisting)

Javascript 공식문서

호이스팅은 인터프리터가 코드를 실행하기 전에 함수, 변수, 클래스 또는 임포트 (import)의 선언문을 해당 범위의 맨 위로 이동시키는 과정을 말합니다.

자바스크립트 공식문서에는 호이스팅을 위와 같이 설명하고 있다.

맨 위로 이동시킨다는 말이 와닿지 않을 수 있는데 쉽게 설명하자면 선언이 코드 실행 전에 메모리에 저장되었다는 말과 같다.

호이스팅은 3단계에 걸쳐서 일어나는데 과정은 아래와 같다.

1. 선언 단계 (Declaration phase)

2. 초기화 단계 (Initialization phase)

3. 할당 단계 (Assignment phase)

자바스크립트에 모든 선언에는 호이스팅이 발생한다. 하지만 let, const, class 에는 호이스팅이 발생하지 않는 것으로 보는데 , 그 이유는 temporal dead zone이 선언 이전의 변수 사용을 엄격하게 금지하고 있기 때문이다.

예를 들면 아래와 같다

const x = 1;
{
  console.log(x); // 참조 에러
  const x = 2;
}

이 코드는 상위 범위에서 x를 읽을 수 있을것 같지만 실제로는 const x = 2 에서 값을 읽어오기 때문에 에러가 발생한다.

Javascript 공식문서

const 선언은 여전히 정의된 전체 범위를 "오염"시키기 때문에 console.log(x) 문은 아직 초기화되지 않은 const x = 2 선언에서 x를 대신 읽어서 ReferenceError를 던집니다.

아래와 같은 경우는 호이스팅의 예제가 아니다

{
  var x = 1;
}
console.log(x); // 1

이 코드에는 "선언 전 접근" 이 없는데, 이는 단순히 var 이 블록으로 범위가 지정되지 않았기 때문이다.

클로저 (Closure)

Javascript 공식 문서

클로저는 주변 상태(어휘적 환경)에 대한 참조와 함께 묶인(포함된) 함수의 조합입니다. 즉, 클로저는 내부 함수에서 외부 함수의 범위에 대한 접근을 제공합니다. JavaScript에서 클로저는 함수 생성 시 함수가 생성될 때마다 생성됩니다.

코드를 보면서 천천히 이해해보자

function makeFunc() {
  const name = "Mozilla";
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc() // Mozilla;

이 코드를 실행시키면 Mozilla 라는 이름이 출력된다. 직관적으로 보자면 함수 안의 지역 변수들은 함수가 실행되는 동안에만 존재하는게 아닌가? 라고 생각할 수 있다.

이와 같은 관점으로 보자면 makeFunc()myFunc()displayName() 을 할당해 주고 없어지기 때문에 myFunc() 를 호출하면 에러가 날 것으로 예상된다.

하지만 결과는 에러 없이 정상적으로 동작하는걸 볼 수 있다. 여기에서 클로저 라는 개념이 등장하는데, javascript에서는 클로저를 형성하기 때문에 name에 접근 할 수 있다.

이처럼 자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지될 경우 외부 함수 밖에서 내부 함수를 호출하더라도 외부 함수의 지역 변수에 접근할 수 있는데, 이를 클로저 라고 한다.

후기

프론트엔드 기술 면접을 준비하면서 스코프, 호이스팅, 클로저에 대한 개념을 공부해 보았다. 이 중에서도 클로저는 스코프, 호이스팅에 대한 개념을 알고 있어야지 이해가 쉽게 되기 때문에 나에게는 어려운 개념중 하나였다.

기술 면접 질문에도 자주 출제되는 개념들인 만큼 자세히 알아보는 시간을 가질수 있어서 좋았다. 여러 블로그 글과 공식 문서를 참고하고 쓴 글이라서 혹시 잘못된 정보가 있으면 피드백을 해주면 좋을것 같다.

© 2023 DoHi0512 powerd by DoHi.log