본문 바로가기

programming study/JavaScript

Scope & Closure

본 내용은 10분 테코톡 엘라님의 강의를 토대로 작성하였습니다.

1. 스코프

스코프란?

  • 변수 이름, 함수 이름, 클래스 이름과 같은 식별자가 본인이 선언된 위치에 따라 다른 코드에서 자신이 참조될 수 있을지 없을지 결정되는 것
    • JavaScript를 포함한 모든 프로그래밍 언어에서 기본적인 개념
  • 전역에서 선언된 경우 -> 전역변수
    • 전역 스코프를 가짐
  • 지역에서 선언된 경우 -> 지역변수
    • 지역 스코프를 가짐

 

스코프 체인

  • 함수의 중첩: 함수는 전역에서 선언될 수도 있고 또다른 함수 내부에서 선언될 수 있음
    • 중첩 함수: 함수 내부에서 선언된 함수
    • 외부 함수: 중첩 함수를 포함하는 함수
    • 함수가 중첩이 된다면 각각 함수의 스코프도 중첩이 됨 -> 스코프가 함수의 중첩에 의해 계층적인 구조를 가질 수 있음
  • 스코프체인: 스코프가 계층적으로 연결되어 있는 것
  • 스코프 체인은 물리적으로 존재
  • 변수를 참조할 때 자바스크립트 엔진 스코프 체인을 통해 변수를 참조
    • 변수를 참조할 때, 해당 스코프에 변수가 없으면 상위 스코프로 올라가 변수를 찾음
    • 전역 스코프까지 연쇄적으로 변수를 찾음
    • 전역 스코프에도 변수가 없으면 ReferenceError 발생
  • 반방향성: 변수를 찾는 것은 상향으로 이뤄짐
let x = "전역변수x";

function outer() {
  let y = "outer함수의 지역변수y";
  console.log(x); // "전역변수x"
  console.log(y); // "outer함수의 지역변수y"

  function inner() {
    let x = "inner함수의 지역변수x";

    console.log(x); // "inner함수의 지역변수x"
    console.log(y); // "outer함수의 지역변수y"
  }

  inner();
}

outer();
console.log(x); // "전역변수x"
console.log(y); // ReferenceError...
// 이 코드의 스코프 체인은 전역 스코프 > outer 지역 스코프 > inner 지역 스코프

 

스코프 종류(스코프 레벨)

  • 블록 레벨 스코프
    • if문, for문, 함수…
    • 대부분의 프로그래밍 언어
    • let, const(JavaScript)
  • 함수 레벨 스코프
    • only 함수
    • var키워드(JavaScript)

 

스코프 종류(스코프가 결정되는 시점)

  • 동적 스코프
    • 함수가 호출되는 시점에 결정
    • 프로그램 런타임 도중 실행 컨텍스트나 호출 컨텍스트에 의해서 결정
  • 정적 스코프
    • 함수가 정의되는 시점에 결정
    • 렉시컬 스코프
    • JavaScript는 이를 따름
    • 함수가 생기자마자 상위 스코프가 결정이 되고 함수 객체가 생성이 되면 해당 함수 객체는 자신의 상위 스코프를 알 수 있음
    • 자신의 내부 슬롯에 상위 스코프의 참조를 저장

 

함수 호출과 스코프

  • 함수 호출
  • 실행 컨텍스트 생성
  • 실행 컨텍스트 스택에 push
  • 함수의 렉시컬 환경 생성
    • 렉시컬 환경: 포함하는 식별자, 식별자에 바인딩 된 값, 상위 레시컬 환경에 대한 참조
    • 코드가 어디서 실행이 되고 본인 주변에 어떤 코드들이 있는지 대체적인 정보를 담고 있음
  • 함수 실행
  • 실행 컨텍스트 스택에서 해당 컨텍스트를 pop

 

2. 클로져

  • 함수의 중첩에서 내부 함수가 생명주기를 마감한 외부 함수의 변수를 참조
    • 이때의 내부함수를 클로져라고 함
  • 클로져
    • 한 중첩함수가 상위 스코프의 식별자를 참조하고 있고
    • 본인의 외부 함수보다 더 오래 살아있는 경우
    • 본인의 상위 스코프에서 참조하고 있는 식별자만 기억
  • 자유변수: 클로저에 의해 참조된 변수
  • 클로져는 하나의 state가 의도치 않게 변경되지 않도록 state를 안전하게 은닉하고 특정 함수에게만 state 변경을 허용하기 위해 사용
const x = 1;

// 중첩 함수 inner를 반환하면서 생명주기를 마감하는 함수, 이때 실행 컨텍스트 스택에서 제거
function outer() {
  const x = 10; // outer의 생명주기가 끝나면 접근할 수 없음
  const inner = function() { // 클로져
    // 생명주기가 끝난 외부함수의 변수를 접근할 수 있음
    console.log(x);
  };

  return inner;
}

const example = outer();
example(); // 10을 출력

 

클로져의 원리

  • outer 생명 주기가 끝나 실행 컨텍스트 스택에서 제거
    • outer 함수의 생명 주기가 종료되어도 해당 함수의 렉시컬 환경은 존재
  • outer 함수는 inner함수를 반환하며 사라짐
  • example 함수는 inner함수 객체를 참조
  • inner함수는 자신의 내부 슬롯에 저장된 outer 함수의 렉시컬 환경을 참조
    • 가비지 컬렉션의 대상이 되지 않음
  • 그 결과, outer함수의 변수를 참조할 수 있게 됨

 

Reference

[10분 테코톡] 엘라의 Scope & Closure

'programming study > JavaScript' 카테고리의 다른 글

ES6 - const & let  (0) 2021.10.19
ES6 & Babel  (0) 2021.10.18
Generator & Iterator (2) - Generator  (0) 2021.10.11
Generator & Iterator (1) - Iteration Interface  (0) 2021.10.10
ES Modules  (0) 2021.09.28