24장 클로저 ⭐⭐⭐⭐⭐⭐⭐
“ A Closure is the combination of a function and the lexical environment within which that function was declared “ 클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.
24.1 렉시컬 스코프
렉시컬 스코프(정적 스코프) - JS 엔진은 함수를 어디에 정의했는지에 따라 상위 스코프를 결정한다.
스코프는 실행 컨텍스트의 렉시컬 환경
이다. 이 렉시컬 환경은 외부 렉시컬 환경에 대한 참조를 통해 상위 렉시컬 환경과 연결되는 스코프 체인
이 된다.
따라서 상위 스코프에 대한 참조는 함수 정의가 평가되는 시점에 함수가 정의된 환경에 의해 결정된다.
24.2 함수 객체의 내부 슬롯 [[Environment]]
함수가 정의된 환경과 호출되는 환경은 다를 수 있다.
따라서 렉시컬 스코프가 가능하려면 함수는 자신이 호출되는 환경과 상관없이 자신이 정의된 환경, 즉 상위 스코프를 기억해야 한다. 이를 위해 함수는 자신의 내부 슬롯 [[Environment]]에 상위 스코프의 참조를 저장한다.
24.3 클로저와 렉시컬 환경
innerFunc 함수에 outer 함수를 호출하면서 inner 함수가 저장된다.
이후 outer 함수는 생명 주기가 종료되어 실행 컨텍스트 스택에서 제거된다.
하지만 innerFunc를 실행해보면 outer 함수의 지역 변수 x가 동작하고 있다.
이처럼 외부 함수보다 중첩 함수가 더 오래 유지되는 경우, 중첩 함수는 생명 주기가 완료된 외부 함수의 변수를 참조할 수 있다. 이러한 중첩 함수를 클로저라 부른다.
사례보기 p.394 ~ p.400
클로저는 중첩 함수가 상위 스코프의 식별자를 참조하고 있고, 중첩 함수가 외부 함수보다 더 오래 유지되는 경우에 한정하는 것이 일반적이다.
클로저에 의해 참조되는 상위 스코프의 변수를 자유 변수라 부른다.
클로저란 “함수가 자유 변수에 대해 닫혀있다”는 의미로, 의역하면 “자유 변수에 묶여있는 함수” 이다.
JS의 강력한 기능으로 필요하다면 적극적으로 사용해야 한다.
24.4 클로저의 활용
클로저는 상태를 안전하게 변경하고 유지하기 위해 사용한다. ⇒ 상태가 의도치 않게 변경되지 않도록 안전하게 은닉하고, 특정 함수에 변경을 허용하기 위해 사용한다.
작동하지만 오류 발생 가능성이 있는 코드이다.
전제 조건 1. 카운트 상태는 increase 함수가 호출되기 전까지 변경되지 않고 유지되어야 함
전제 조건 2. 이를 위해 카운트 상태는 increase 함수만이 변경할 수 있어야 한다.
⇒
상태를 안전하게 변경하고 유지하기 위해 변수를 함수의 지역 변수로 변경했지만, 상태가 변경되기 이전 상태를 유지하지 못한다.
⇒ 클로저 사용
즉시 실행 함수가 호출되고, 반환한 함수가 increase 변수에 할당된다. increase 변수에 할당된 함수는 상위 스코프인 즉시 실행 함수의 렉시컬 환경을 기억하는 클로저로 num의 상태를 기억하고 있다. 그리고 즉시 실행 함수로 한번만 실행되므로 num 변수가 초기화될 일도 없고, 외부에서 num에 접근할 수도 없는 private한 변수이므로 더 안정적인 프로그래밍이 가능하다.
이처럼 클로저는 상태가 의도치 않게 변경되지 않도록 안전하게 은닉하고 특정 함수에만 상태 변경을 허용하여 상태를 안전하게 변경하고 유지하기 위해 사용한다.
특히, 에서 부수 효과를 최대한 억제하여 오류를 피하고 프로그램의 안정성을 높이기 위해 적극적으로 사용된다.
24.5 캡슐화와 정보 은닉
캡슐화는 프로퍼티와 메서드를 하나로 묶는 것과 특정 프로퍼티나 메서드를 은닉하기 위해 사용하는 개념이다.
정보 은닉은 외부에 공개할 필요가 없는 구현의 일부를 공개되지 않도록 적절히 감춰 상태 변경을 방지해 정보를 보호하고, 결합도를 낮추는 효과가 있다.
접근 제한자를 사용해 정보 은닉을 실현하는 타 언어와 달리 JS는 객체의 모든 프로퍼티와 메서드가 공개되어 있다. 이를 방지하기 위해 클로저 개념을 사용해 정보를 은닉한다. 하지만 완전한 은닉은 불가능하다.
24.6 자주 발생하는 실수
var 키워드로 변수를 선언하면 클로저가 실행되지 않기에 let 이나 const 키워드를 사용해 변수를 선언하고 코드 블록 내에서 함수를 정의해야 한다.
혹은 고차 함수를 사용해 함수형 프로그래밍 기법을 사용하는 것이 좋다.
Last updated
Was this helpful?