[JS] 클로저란? 중첩함수?

hahaha·2021년 8월 9일
1

JavaScript

목록 보기
10/24
post-thumbnail

들어가기 전에

렉시컬 스코프(정적 스코프)

  • JS 엔진은 함수를 어디서 호출했는지가 아닌 함수를 어디에 정의했는지에 따라 상위 스코프를 결정

스코프

  • 실행 컨텍스트의 렉시컬 환경

"함수의 상위 스코프를 결정한다"

= "렉시컬 환경의 외부 렉시컬 환경에 대한 참조에 저장할 참조값을 결정한다"

함수 객체의 내부 슬롯 [[Environment]]

  • 함수는 자신의 내부 슬롯 [[Environment]]에 자신이 정의된 환경,
    상위 스코프의 참조를 저장
  • 함수 객체를 생성하는 시점은 함수가 정의된 환경, 즉 상위 함수가 평가 or 실행되고 있는 시점
    -> 현재 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조 = 상위 스코프

함수 코드 평가 순서

  1. 함수 실행 컨텍스트 생성
  2. 함수 렉시컬 환경 생성
    2.1. 함수 환경 레코드 생성
    2.2. this 바인딩
    2.3. 외부 렉시컬 환경에 대한 참조 결정
    -> [[Environment]]에 저장된 렉시컬 환경의 참조

클로저

  • 중첩함수가 상위 스코프의 식별자를 참조하고 있고, 외부 함수보다 더 오래 유지되는 경우에서의 중첩함수
  • 외부 함수보다 중첩 함수가 더 오래 유지되는 경우, 중첩 함수는 이미 생명주기가 종료된 외부 함수의 변수를 참조할 수 있다.
    - 외부 함수의 실행 컨텍스트가 실행 컨텍스트에서 제거되는 것 뿐
    - 중첩 함수가 참조하는 외부 함수의 렉시컬 환경까지 소멸되지 않기 때문
  • JS만의 고유 개념은 아님
  • 실행 컨텍스트와 밀접한 관련이 있음

MDN에서의 클로저 정의

"A closure is the combination of a function and the lexical environment within which that fuction was declasred"

  • 자유변수: 클로저에 의해 참조되는 상위 스코프의 변수
  • JS 엔진의 최적화로 인해 클로저가 참조하고 있지 않은 식별자는 기억 X

활용

  • 상태를 안전하게 변경 / 유지하기 위해 사용
  • 의도치 않게 변경되지 않도록 상태 은닉

예시

const increase = (function () {
  let num = 0;
  // 클로저
  return function () {
    return ++num;
  }
}());
console.log(increase());	// 1
console.log(increase());	// 2
  • 즉시 실행 함수는 한 번만 실행되므로
    increase가 호출될 때 마다 num 변수가 재차 초기화 되지 않음
  • num 변수는 외부에서 접근할 수 없는 은닉된 변수 -> 의도치 않은 변경 막을 수 있음

캡슐화와 정보 은닉

캡슐화: 프로퍼티와 메서드를 하나로 묶는 것

  • 객체의 특정 프로퍼티나 메서드를 감출 목적으로 사용 -> 정보 은닉
  • 대부분의 객체지향 프로그래밍 언어는 접근 제한자 사용 -> 공개 범위 한정
  • JS는 접근 제한자 제공 X

- 접근 제한자 없이 정보은닉하기

const Person = (function () {
  let _age = 0;	// private
  
  // 생성자 함수 -> 클로저
  function Person(name, age) {
    this.name = name;	// public
    _age = age;
  }
  
  // (인스턴스 메서드가 아닌) 프로토타입 메서드 -> 클로저
  Person.prototype.sayHi = function() {
    console.log(`Hi My name is ${this.name}. I am ${_age}.`);
  };
  
  return Person;
}());

const me = new Person('Lee', 20);
me.sayHi();	// Hi My name is Lee. I am 20.
console.log(me.name);	// Lee
console.log(me._age); 	// undefined

+) 여러 개의 인스턴스를 생성할 경우 정보 은닉 완벽하게 지원 X

profile
junior backend-developer 👶💻

0개의 댓글