2020. 9. 28. 22:24ㆍFrontend
Interview Section은 FrontEnd Interview Question에 대한 QnA를 다룹니다.
Q. What is a closure, and how/why would you use one?
+ What is Lexical Scoping?
A.
클로저란, 함수와 함수가 선언된 정적 환경의 조합을 의미합니다. 이를 제대로 설명하기 위해서는 렉시컬 스코프(Lexical Scope)에 대해 먼저 설명해야 합니다.
자바스크립트에서는 코드의 위치가 정해지는 순간, 그 코드 안에 포함된 변수의 유효 범위(Scope)가 정해지는 정적인 특성을 가지고 있습니다. 이것을 정적 유효 범위, 혹은 렉시컬 스코프(Lexical Scope)라고 말합니다. 간단히 말하자면 함수안에서 정의된 변수는 함수 밖으로 빠져나갈 수 없다는 것입니다.
렉시컬 스코프를 이해하기 위해 MDN에서는 다음과 같은 예시를 들고 있습니다.
function init() {
var name = 'Mozila'; // name 은 init에 의해 생성된 지역 변수입니다.
function displayName() {
alert(name); // 실행 컨텍스트의 스코프 체이닝에 의해 부모 함수의 name을 사용합니다.
}
displayName();
}
init();
위 코드를 브라우저에서 실행하면 브라우저는 정상적으로 'Mozila'를 출력합니다.
displayName()은 init()안에서 선언된 함수이고 자신만의 지역 변수가 없습니다. 자바스크립트의 실행 컨텍스트가 생성될 때 스코프 체인을 만들기 때문에 displayName() 안에 선언된 name이라는 변수가 없다면 스크립트는 스코프 체인의 다음 리스트에 있는 init의 스코프에서 name을 찾습니다. 여기에는 "Mozila"라는 값을 갖는 변수가 있으므로 이 값을 사용합니다.
앞서 정의했듯, 클로저는 함수와, 함수가 선언된 어휘적 환경(정적 환경, Lexical Scope)의 조합이기 때문에 다음과 같이 함수를 작성해도 위와 동일한 결과가 나옵니다.
function funcFactory() {
var name="Mozila";
function displayName() {
alert(name);
}
return displayName;
}
var item = funcFactory();
// item에는 funcFactory의 lexical scope가 유지됩니다.
item();
위 코드를 보면, name은 funcFactory가 실행될 때, 이미 그 스코프를 잃어버렸기 때문에 item을 실행했을 때는 에러가 발생할 것이라고 생각할 수 있지만, funcFactory가 선언되는 시점에서 리턴되는 displayName의 함수가 클로저(함수와, 함수가 선언된 어휘적 환경, 여기서는 funcFactory의 지역변수를 포함)를 형성하기 때문에 정상적으로 "Mozila"를 출력합니다.
item은 funcFactory가 실행될 때 생성된 displayName의 인스턴스에 대한 참조입니다. 이 인스턴스는 앞서 말했듯, 클로저이기 때문에, 선언되었을 시점의 언어적 환경에 대한 참조를 유지하고 있습니다. 따라서 item이 호출될 때 변수 name은 사용 가능한 상태로 남게 되는 것입니다.
클로저는 자바스크립트에서 가장 중요한 특징 중 하나입니다. 이를 이용해서 팩토리 패턴, 커링 패턴 등의 여러 패턴들을 사용할 수 있습니다. 리액트 라이브러리로 프론트엔드 앱을 개발할 때 가장 많이 사용되는 상태 관리 라이브러리인 리덕스(Redux)도 클로저를 사용하여 상태의 불변성 (Immutability)를 유지합니다.
Reference
developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Closures
'Frontend' 카테고리의 다른 글
[Javascript] Attribute vs Property (1) | 2020.09.29 |
---|---|
[Javscript] 함수 스코프 vs 블록 스코프 (0) | 2020.09.29 |
[Javascript] 호이스팅이란 (0) | 2020.09.28 |
[Javascript] forEach vs map (Array.prototype) (0) | 2020.09.27 |
[Javascript] 자바스크립트에서의 This (0) | 2020.09.24 |