JS/[책] 모던 자바스크립트 Deep Dive

24. 클로저

배워도끝이없네 2021. 10. 12. 18:31

- 클로저에서 먼저 이해해야 할 핵심 키워드는 "함수가 선언된 렉시컬 환경"이다.

 

const x = 1;

function outerFunc(){
	const x = 10;
    innerFunc();
}

function innerFunc(){
	console.log(x); //1 함수는 자신이 선언된 상위스코프만 참조할 수 있다.
}

outerFunc();

 

1. 렉시컬 스코프

- 자바스크립트 엔진은 함수를 어디서 호출했는지가 아니라, 함수를 어디에 정의했는지에 따라 상위 스코프를 결정한다. 이를 렉시컬 스코프(정적 스코프)라 한다.

- 스코프의 실체는 실행컨텍스트의 렉시컬 환경이다.

- 렉시컬환경은 자신의 "외부 렉시컬 환경에 대한 참조"를 통해 상위 렉시컬 환경과 연결된다. 이것이 스코프체인이다.

- 렉시컬 환경의 외부 렉시컬 환경에 대한 참조"에 저장할 참조값은(스코프) 함수 정의가 평가되는 시점에 함수가 정의된 위치에 의해 결정된다. 이것이 렉시컬 스코프이다.

 

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

- 함수는 자신의 내부 슬롯 [[Environment]]에 자신이 정의된 환경, 즉 상위 스코프의 참조를 저장한다.

- 함수 내부에 정의된 함수 표현식은 외부 함수 코드가 실행되는 시점에 평가되어 함수 객체를 생성한다..

const x = 1;

function foo(){
	const x = 10;
    
    bar();
}

function bar(){
	console.log(x);
}

foo(); //
bar(); // bar함수는 자신이 평가될 때 [[Environment]]에 자신의 상위 렉시컬 스코프를 저장한다.

- 외부 렉시컬 환경에 대한 참조에는 함수 객체의 내부 슬롯 [[Environment]]에 저장된 렉시컬 환경의 참조가 할당된다.

 

3. 클로저와 렉시컬 환경

- 함수를 호출하면 함수는 자신의 코드를 모두 실행하고 난 뒤에 생명주기 (life cycle)을 마감한다.

- 하지만 중첩함수를 반환받아 외부에서 참조하고 있다면, 중첩함수가 외부함수보다 오래 유지되는 경우가 생기는데, 이렇게 생명주기가 이미 종료된 외부함수의 변수를 참조하는 중첩 함수를 클로저라고 한다.

- 모든함수는 자신의 상위 스코프를 기억할 수 있고, 모든 함수는 자신의 상위스코프의 식별자를 어디에서나 참조할 수 있으며, 식별자에 바인딩 된 값을 변경할 수 있다.

-가비지 컬렉터는 참조되고있는 대상은 메모리공간을 해제하지 않기 때문에 외부에서 중첩함수가 참조하는 외부함수의 변수를 해제하지 않는다.

- 중첩함수는 외부함수보다 오래 생존할 때 외부함수의 생존 여부와는 상관 없이 자신이 정의된 위치에서 결정된 상위 스코프를 기억하고 참조할 수 있다.

- 중첩함수가 외부함수보다 오래 생존하더라도, 중첩함수가 외부함수의 인자를 참조하지 않으면, 대부분의 브라우저들은 최적화를 통해 상위스코프를 기억하지 않는다.

- 클로저는 중첩 함수가 상위 스코프의 식별자를 참조하고 있고, 중첩 함수가 외부 함수보다 더 오래 유지되는 경우에로 한정하는 것이 일반적이다.

- 클로저에 의해 참조되는 상위 스코프의 변수를 자유변수라고 부른다.

- 클로저(slosure)란, "함수가 자유변수에 대해 닫혀있다". 라는 의미이다. 쉽게 의역하면 "자유변수에 묶여있는 함수"라고 할 수 있다.

 

4. 클로저의 활용

- 클로저는 상태를 안전하게 변경하고 유지하기 위해 사용한다.(은닉)

const increase = (function(){
	let num = 0;
    return function(){
    	return ++num;
    }
}());

console.log(increase()); //1
console.log(increase()); //2
console.log(increase()); //3 상태를 유지할 수 있으며 외부에서 변수에 직접 접근할 수 없다

 

 5. 캡슐화와 정보 은닉

- 캡슐화는 객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 동작인 메서드를 하나로 묶는 것을 말한다.

- 캡슐화는 객체의 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데 이를 정보 은닉이라 한다.

- 자바스크립트는 모든 객체의 프로퍼티와 메서드에 대해 퍼블릭하다.

 

6. 자주 발생하는 실수

var funcs = [];

for (var i = 0 ; i < 3; i++){ //var은 function scope를 갖기 때문에 i를 return하면 전역의 i를 호출하게 된다.
	funcs[i] = function(){return i;};
}

for (var j = 0 ; j < juncs.length; j++){
	console.log(funcs[j]());
}

for문의 변수 선언문에서 let 키워드를 사용하면 for문의 코드블록이 반복 실행할 때마다 각각의 렉시컬 환경을 생성한다.

 

'JS > [책] 모던 자바스크립트 Deep Dive' 카테고리의 다른 글

23. 실행 컨텍스트  (1) 2021.09.14
22. this  (0) 2021.09.08
21. 빌트인 객체  (0) 2021.09.07
20. strict mode  (0) 2021.09.07
19. 프로토타입  (0) 2021.09.06