Closure
클로저란 자바스크립트에 있어서 C언어의 포인터와 같은 관점으로 볼 수 있습니다. 먼저 scope chain에 대해 알아야 합니다.
scope chain
scope는 비동기 함수가 호출될 때까지 계속해서 지속되어 참고가 됩니다.(scope의 지속성) 새로운 scope를 생성함으로써 비동기적으로 호출 될 때의 scope를 조율할 수 있습니다.
아래의 예제에서는 outer() 함수 호출 후 inner() 내에 변수 a 에 x 를 대입할 때 실행문을 포함하고 있는 함수의 변수 스코프부터 먼저 검색됩니다. 만약 없는 경우 상위 스코프로 검색을 시작하게 되며 전역 스코프에도 없는 경우 에러를 발생시킵니다.
var x = 1;function outer() {function inner() {}outer();
Clusure
클로저란 함수가 함수 내부에 선언된 변수에 접근할 수 있는 함수를 말합니다.
클로저는 독립적인 (자유)변수를 가리키는 함수이며 클로저 안에 정의된 함수는 만들어진 환경을 '기억'합니다.
아래의 예제를 통해 알아보겠습니다.
function makeFunc() {function displayName() {return displayName;}var myFunc = makeFunc();myFunc();
위의 예제에서 name 변수는 makeFunc라는 함수 스코프에 존재합니다. 즉 함수 외부에서는 접근을 할 수 없습니다. 하지만 displayName라는 함수 내부의 함수를 name가 name 변수를 참조하게 하여 함수 외부에서도 접근할 수 있도록 return 을 하여 myFunc() 함수에서도 name을 접근할 수 있습니다.
생성 시 환경을 기억하는 클로저
클로저는 만들어질 때의 환경을 기억합니다. 다음 예제를 살펴보도록 하겠습니다.
var i;for (i = 0; i < 10; i++) {}
위 예제는 0~9까지의 출력을 예상할 수 있지만 setTimeout 함수에 의해 0.1초를 기다리는 동안 i가 10번을 돌게 되어 익명 함수 호출시에는 i가 이미 10이 되어 10을 10번 출력하게 됩니다.
이 상황을 클로저를 이용하여 생성 당시의 환경(i의 값)을 기억하도록 하여 setTimeout 함수에 의해 0.1초 후 익명함수가 호출되더라도 기억하고 있는 i의 값을 출력합니다.
var i;for (i = 0; i < 10; i++) {}
객체와 클로저를 이용한 데이터 은닉
일반적으로 객체를 정의할 때 prototype을 이용하지만 이 방법을 사용하게 되면 외부로부터 데이터를 보호할 수 없게 됩니다.
function Hello(name) {}Hello.prototype.say = function() {}var hello = new Hello("person");hello._name = "person2";
이 경우 클로저를 이용하여 외부로부터 데이터를 보호할 수 있습니다.
function Hello(name) {return function() {}var hello = Hello("person");hello();
Object VS Closure
먼저 객체 생성 시 객체의 프로토타입을 연결하는 방식이 더 좋다. 그 이유는 Object를 사용하게되면 생성자가 호출 될 때마다 메서드가 다시 할당된다.
function MyObject(name, message) {this.message = message.toString();this.getName = function() {}
클로저를 이용하게 되면 이 부분을 보완할 수 있으며 prototype에 다시 정의하는 방법보다 기존 프로토타입에 정의를 하는 것이 좋습니다.
function MyObject(name, message) {this.message = message.toString();}/*MyObject.prototype = {getMessage: function() {};*/MyObject.prototype.getName = function() {};MyObject.prototype.getMessage = function() {};
위 코드에서 즉시 함수 실행 기법 을 사용하면 더 좋은 성능을 얻을 수 있습니다. (함수 표현은 함수 정의 및 저장 후 실행하는 과정을 거치지만 즉시 실행함수를 사용하게 되면 함수 정의 후 바로 실행하여 위의 과정을 거치지 않습니다.)
function MyObject(name, message) {this.message = message.toString();}(function() {this.getMessage = function() {}).call(MyObject.prototype);
클로저 사용 후 정리하기
c 와 c++ 에서 동적할당 후 마지막에 동적해제하는 과정을 거칩니다. 그 이유는 메모리를 회수하기 위함입니다. 자바스크립트에서는 스코프 체인 성질에 의해 어떠한 변수 혹은 함수가 참조를 하고 있으면 내부 변수가 차지하는 메모리를 GC(Garbage Collector)가 회수하지 않습니다. 따라서, 클로저 사용 후 참조를 제거하는 것이 좋습니다.
hello = null;
'Language > Javascript' 카테고리의 다른 글
promise - 2 [Promise 사용 시 주의할 것] (0) | 2017.07.28 |
---|---|
promise - 1 [then, catch, resolve, reject] (0) | 2017.07.28 |
scope - 3 [변수 숨기기] (0) | 2017.07.28 |
Scope - 2 [정적, 동적, 블록, 중첩 스코프] (0) | 2017.07.21 |
Scope - 1 [스코프란 무엇일까?] (0) | 2017.07.21 |