increase, decrease를 품은 객체 리터럴은 상위 스코프로 즉시실행함수를 가지며 즉시실행 함수보다 오래 살아남기 때문에 클로저이다.
캡슐화와 정보 은닉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
functionPerson(name, age) { this.name = name; // public let _age = age; // private
// 인스턴스 메서드 this.sayHi = function () { console.log(`Hi! My name is ${this.name}. I am ${_age}.`); }; }
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
const you = new Person("Kim", 30); you.sayHi(); // Hi! My name is Kim. I am 30. console.log(you.name); // Kim console.log(you._age); // undefined
_age 변수는 private하다.
위 예제의 sayHi 메서드는 인스턴스 메서드이므로 Person 객체가 생성될 때마다 중복 생성된다. sayHi 메서드를 프로토타입 메서드로 변경하여 sayHi 메서드의 중복 생성을 방지해 보자.
1 2 3 4 5 6 7 8 9 10
functionPerson(name, age) { this.name = name; // public let _age = age; // private }
// 프로토타입 메서드 Person.prototype.sayHi = function () { // Person 생성자 함수의 지역 변수 _age를 참조할 수 없다 console.log(`Hi! My name is ${this.name}. I am ${_age}.`); };
즉시 실행 함수의 매개변수 id는 즉시 실행 함수가 반환한 중첩 함수의 상위 스코프에 존재한다. 즉시 실행 함수가 반환한 중첩 함수는 자신의 상위 스코프(즉시 실행 함수의 렉시컬 환경)를 기억하는 클로저이고, 매개변수 id는 즉시 실행 함수가 반환한 중첩 함수에 묶여있는 자유 변수가 되어 그 값이 유지된다.
ES6의 let 키워드를 사용하면 이와 같은 번거로움이 깔끔하게 해결된다.
1 2 3 4 5 6 7 8 9 10 11
const funcs = [];
for (let i = 0; i < 3; i++) { funcs[i] = function () { return i; }; }
for (let i = 0; i < funcs.length; i++) { console.log(funcs[i]()); // 0 1 2 }
for 문의 변수 선언문에서 let 키워드로 선언한 변수를 사용하면 for 문의 코드 블록이 반복 실행될 때마다 for 문 코드 블록의 새로운 렉시컬 환경이 생성된다. 만약 for 문의 코드 블록 내에서 정의한 함수가 있다면 이 함수의 상위 스코프는 for 문의 코드 블록이 반복 실행될 때마다 생성된 for 문 코드 블록의 새로운 렉시컬 환경이다.