let count = 0;
function increment() {
}
함수 스코프({}
) 밖에 변수가 하나 있네요.
당연하게도, 아래처럼 increment
함수 안에서 count
변수에 접근할 수 있습니다.
let count = 0;
function increment() {
count = count + 1;
console.log(`count의 값은 ${count}`);
}
increment(); // 출력: count의 값은 1
increment(); // 출력: count의 값은 2
increment()
가 잘 작동하네요.
그런데,
count
는 다른 함수들에서도 접근할 수 있죠.
그러다가 count
값이 도중에 변경되면?
increment(); // 출력: count의 값은 1
count = 100;
increment(); // 출력: count의 값은 101
increment()
가 호출될 때만 count
가 1
씩 증가하는 게 의도였는데 어긋났어요.
둘을 좀 더 강하게 엮을 순 없을까요?
increment()
만 count
에 접근할 수 있도록 말이에요.
있습니다.
increment()
함수를 반환하는 새로운 함수를 만들면 됩니다.
function counter() {
let count = 0;
function increment() {
count = count + 1;
console.log(`count의 값은 ${count}`);
}
return increment;
}
increment()
함수를 반환하는 새로운 함수 counter()
를 만들었어요.
좀 전에 봤던 count
와 increment()
코드가 그대로 counter()
함수 안에 있고
counter()
함수는 그냥 increment()
함수를 반환합니다.
그럼 한번 counter()
한테서 increment()
를 받아 사용해 볼까요?
const increment = counter();
increment(); // 출력: count의 값은 1
increment(); // 출력: count의 값은 2
increment()
함수만 반환받아 사용했는데 count
의 값이 정상적으로 변하네요.
이제 count
값을 마음대로 변경할 수 없어요. count
가 counter()
함수 안에 있어서 외부에서 접근할 수 없거든요.
그런데 count
가 counter()
함수 스코프에서 만들어지는 변수라면,
첫 번째 줄에서 counter()
함수 실행이 끝났을 때 사라져야 하는 거 아닌가요?
우린 방금 클로저가 만들어지도록 코딩한 겁니다!
counter()
함수를 호출할 때 클로저가 만들어집니다.
클로저가 만들어지면 위처럼 counter()
함수 실행이 끝난 뒤에도 count
에 increment()
가 계속 접근할 수 있어요.
이렇게 우리는 클로저를 활용해서 increment()
함수를 통해서만 count
에 접근할 수 있도록 감춰버렸어요.
C++나 Java 등의 클래스에서의 private
같기도 하네요.
counter()
에 아래처럼 기능을 추가해 볼 수도 있답니다.
function counter() {
let count = 0;
function increment() {
count = count + 1;
console.log(`count: ${count}`);
}
function decrement() {
count = count - 1;
console.log(`count: ${count}`);
}
return {
increment,
decrement
};
}
먼저 다음과 같은 데이터가 있습니다.
const people = [
{ id: 1, name: '마석도', email: 'ma@gmail.com' },
{ id: 4, name: '이지안', email: 'lee@gmail.com' },
{ id: 6, name: '박새로이', email: 'park@gmail.com' }
];
people.filter()
를 사용하여 특정한 사람을 제외한 데이터를 구하고 싶다면,
people.filter((person) => person.name !== '박새로이');
people.filter((person) => person.name !== '마석도');
보통 위처럼 코드를 작성합니다.
filter()
에 전달하는 함수(predicate)를 클로저를 활용해서 추상화해봅시다. (Currying)
const excludePersonWithName = (뺄사람이름) => (person) => person.name !== 뺄사람이름;
people.filter(excludePersonWithName('박새로이'));
people.filter(excludePersonWithName('마석도'));
const excludePersonWithEmail = (email) => (person) => person.email !== email;
people.filter(excludePersonWithEmail('park@gmail.com'));
people.filter(excludePersonWithEmail('ma@gmail.com'));
const excludePersonWith = (propertyName) => (propertyValue) => (person) =>
person[propertyName] !== propertyValue;
const excludePersonWithName = excludePersonWith('name');
people.filter(excludePersonWithName('박새로이'));
people.filter(excludePersonWith('name')('마석도'));
const excludePersonWithEmail = excludePersonWith('email');
people.filter(excludePersonWithEmail('park@gmail.com'));
people.filter(excludePersonWith('email')('ma@gmail.com'));