클로저(Closure)

최관수·2023년 10월 19일
0

기술면접심화

목록 보기
1/6

스코프

  • 변수와 함수, 클래스 이름과 같은 식별자가 본인이 선언된 위치에 따라서 자신이 참조 가능 여부가 결정되는 것 → 스코프의 속성이라고 한다면 정적 스코프와 동적 스코프
  • 자바스크립트에서 어떤 함수가 있을 때 그 함수의 유효 범위는 그 함수가 어디서 실행했느냐가 아니라 어디서 정의됐느냐에 따라 달라짐 → 정적 스코프(렉시컬 스코프)
  • 스코프의 범위는 선언되는 위치에 따라 전역 스코프, 지역 스코프

스코프 체인

스코프 체인 예시

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 ..
  • 함수는 전역에서 선언될 수 있지만, 함수의 내부에서도 함수가 선언될 수 있음
  • 함수 내부에서 정의된 함수를 중첩 함수 혹은 내부 함수라고 하고, 중첩 함수를 포함하는 함수는 외부 함수
  • 즉, 스코프 또한 중첩이 될 수 있고 스코프가 계층적인 구조를 가질 수 있다는 것을 의미 → 스코프 체인
  • 변수를 참조할 때 자바스크립트는 스코프 체인을 통해 변수를 참조 → 최상위 전역 스코프까지 확인했을 때 해당 변수가 없을 때에는 reference error를 출력
  • 작업 시 하위 스코프에서 상위 스코프 변수를 참조할 수 있는 이유가 스코프 체인의 단방향성 때문

스코프 레벨

  • 블록 레벨 스코프 - if문, for문, 함수 등
  • 함수 레벨 스코프 - only 함수
  • 상위 스코프를 결정 짓는 요소
    • 동적 스코프 → 함수가 호출되는 시점에 결정 → 런타임 도중에 실행 컨텍스트에 의해서 스코프가 결정
    • 정적 스코프 → 함수가 선언되는 시점에 결정 → 렉시컬 스코프 → 자바스크립트는 렉시컬 스코프를 따르기 때문에 선언되는 시점에 상위 스코프가 결정, 함수 본인의 내부 슬롯에 상위 스코프에 대한 참조를 저장
  • 함수 호출 → 실행 컨텍스트 생성 → 실행 컨텍스트 스택에 푸쉬 → 렉시컬 환경 생성 → 코드의 실행이 끝나면 실행 컨텍스트 스택 제거

클로저

  • 중첩 함수가 상위 스코프의 식별자를 참조하고 있고, 본인의 외부 함수보다 더 생명주기가 길다면 이 중첩 함수는 클로저
  • 외부 함수가 내부 함수보다 먼저 생명주기가 끝나더라도 내부 함수가 외부 함수의 변수를 참조하는 것
  • 가비지 컬렉터와도 관련 → 가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 그 값은 수집 대상에 포함되지 않음, 외부 함수의 실행이 종료되더라도 내부 함수를 실행함으로써 호출될 가능성이 열린 것 → 즉, 내부 함수의 실행 컨텍스트가 활성화되면 외부 함수의 렉시컬 환경이 필요할 것이기 때문에 수집 대상에서 제외
  • closure라는 이름처럼 state를 안전하게 은닉하고, 특정 함수에게만 state 변경을 허용하기 위해 사용한다고 볼 수 있음
  • 클로저를 활용한 은닉화 사례
    function makeCounter() {
    	let num = 0;
    
    	return function () {
    		return num++;
    	}
    }
    
    let counter = makeCounter();
    
    console.log(counter()); // 0
    console.log(counter()); // 1
    console.log(counter()); // 2
  • 덧셈이라고 하는 함수를 더하기함수공장 안에서 호출한 것이 아닌데도 더하기함수공장의 1이라고 하는 값을 내부적으로 스코프로 간직하고 있으니 접근 가능하다는 문법적 요소
    function 더하기함수공장(초기값) {
    	function 덧셈(숫자) {
    		return 초기값 + 숫자;
    	}
    	return 덧셈;
    }
    
    let 더하기1 = 더하기함수공장(1);
    console.log(더하기1(1));
    console.log(더하기1(2));
    
    let 더하기2 = 더하기함수공장(2);
    console.log(더하기2(1));
    console.log(더하기2(2));
    

참고자료

profile
평소엔 책과 영화와 음악을 좋아합니다. 보편적이고 보통사람들을 위한 서비스 개발을 꿈꾸고 있습니다.

0개의 댓글