면접 단골 질문!!
클로저는 내부 함수에서 자유 변수를 가리키고 있는 함수를 의미합니다.
그래서 주로 캡슐화가 필요한 로직에 사용합니다.
하지만, 가비지 컬렉터에 회수되지 못하고 메모리가 낭비되는 현상이 발생합니다.
null
값을 입력하여 클로저 패턴을 끊어줘야 한다.function outer() {
let a = 10; // 자유 변수(free variable)
return function inner() {
// function inner()만 작성하면 함수를 반환하는 것이 아님
// console.log(a)를 반환하게 됨
a++;
console.log(a);
};
}
const fn = outer();
console.log(fn); // [Function: inner]
fn(); // 11
let count = 0;
function counter() {
return {
increment: function () {
count++;
return count;
},
decrement: function () {
count--;
return count;
},
};
}
let mycount = counter();
console.log(mycount.increment()); // 1
count = 20;
console.log(mycount.increment()); // 21
mycount = null;
// 캡슐화가 되지 않아 외부에서 조작이 가능함
// 변수 값을 함수 내부로 은닉화 필요
function counter() {
let count = 0; // count가 캡슐화(은닉화) 된 것
return {
increment: function () {
count++;
return count;
},
decrement: function () {
count--;
return count;
},
};
}
let mycount = counter();
console.log(mycount.increment()); // 1
count = 20; // 외부 조작 적용 안 됨
console.log(mycount.increment()); // 2
mycount = null;
// 안전한 변수를 만들 수 있다. 이런 경우 클로저를 사용함
function makeMultiple(multipler) {
// multipler가 클로저되는 것
return function (x) {
return x * multipler;
};
}
let double = makeMultiple(2);
let triple = makeMultiple(3);
console.log(double(5)); // 5 * 2
console.log(triple(5)); // 5 * 3
// 은닉화를 기본으로 깔면서 특정기능 함수를 고정
double = null; // 메모리 해제, 자유변수 제거
triple = null; // 메모리 해제, 자유변수 제거
function fetcData(url) {
let result;
return function (callback) {
setTimeout(() => {
result = "Fetched... success";
callback(result);
}, 1000); // 1초 뒤에 실행
};
}
let fetchFromNaver = fetcData("https://www.naver.com");
fetchFromNaver((data) => console.log(data));
fetchFromNaver = null;
function memoization(fn) {
const cache = {};
return function (...args) {
const key = JSON.stringify(args);
// 객체나 배열을 json 문자로 바꿔주는 것(문자열로 취급됨)
if (cache[key]) return cache[key];
const result = fn(...args);
cache[key] = result;
return result;
};
}
function slowFunction(num) {
for (let i = 0; i < 9999999999; i++);
return num * 2;
}
let memoizationFn = memoization(slowFunction);
console.log(memoizationFn(5)); // 7.211초
console.log(memoizationFn(5)); // 여기부터는 빠르게 바로 출력됨
console.log(memoizationFn(5));
console.log(memoizationFn(5));
memoizationFn = null;
// 기능을 다 쓰고 나면 항상 메모리 해제를 해줘야 함
설명: 클로저를 이용해 카운터 함수를 만드세요.
이 함수는 호출할 때마다 1씩 증가하는 값을 반환해야 합니다.
function createCounter() {
// 여기에 코드를 작성하세요
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
function createCounter() {
let a = 0;
return function inner() {
a++;
return a;
};
}
let counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
counter = null;
// 강사님 풀이
function createCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
let counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
counter = null;
설명: 숫자를 제곱하는 함수를 만들고, 같은 숫자가 호출될 경우 결과를 캐싱하여 효율적으로 반환하세요.
function square() {
// 여기에 코드를 작성하세요
}
console.log(square(4)); // 16
console.log(square(4)); // 16 (캐시 사용)
console.log(square(5)); // 25
function square(fn) {
const cache = {};
return function (...args) {
const key = JSON.stringify(args);
// 객체나 배열을 json 문자로 바꿔주는 것(문자열로 취급됨)
if (cache[key]) return cache[key];
const result = fn(...args);
cache[key] = result;
return result;
};
}
function slowFunction(num) {
function inner() {
num **= 2;
return num;
}
return inner();
}
let squareFn = square(slowFunction);
console.log(squareFn(4)); // 16
console.log(squareFn(4)); // 16 (캐시 사용)
console.log(squareFn(5)); // 25
squareFn = null;
// 강사님 풀이
function squarec() {
const cache = {};
return function (num) {
if (cache[num]) return cache[num];
cache[num] = num * num;
return cache[num];
};
}
let square = squarec();
console.log(square(4)); // 16
console.log(square(4)); // 16 (캐시 사용)
console.log(square(5)); // 25
square = null;
설명: 주어진 시간 후에 실행되는 함수를 반환하는 클로저를 작성하세요.
function delayExecution(ms) {
// 여기에 코드를 작성하세요
}
const delayedFunc = delayExecution(1000);
delayedFunc(() => console.log("Executed after 1 second"));
강사님 풀이
function delayExecution(ms) {
return function (callback) {
setTimeout(callback, ms);
};
}
let delayedFunc = delayExecution(1000);
delayedFunc(() => console.log("Executed after 1 second"));
delayedFunc = null;
설명: 고유한 ID를 생성하는 함수를 만드세요. 각 호출마다 증가하는 ID를 반환해야 합니다.
function createIdGenerator() {
// 여기에 코드를 작성하세요
}
const getId = createIdGenerator();
console.log(getId()); // 1
console.log(getId()); // 2
console.log(getId()); // 3
강사님 풀이
function createIdGenerator() {
let id = 0;
return function () {
id++;
return id;
};
}
let getId = createIdGenerator();
console.log(getId()); // 1
console.log(getId()); // 2
console.log(getId()); // 3
getId = null;
설명: 피보나치 수열을 계산하는 함수를 만들고, 결과를 메모이제이션하여 성능을 개선하세요.
function fibonacci() {
// 여기에 코드를 작성하세요
}
console.log(fibonacci(10)); // 55
console.log(fibonacci(10)); // 55 (메모이제이션 사용)
function fibonacciC() {
const cache = {};
return function fib(n) {
if (n <= 1) return n;
if (cache[n]) return cache[n];
cache[n] = fib(n - 1) + fib(n - 2);
return cache[n];
};
}
let fibonacci = fibonacciC();
console.log(fibonacci(10)); // 55
console.log(fibonacci(10)); // 55 (메모이제이션 사용)
fibonacci = null;
설명: 문자열을 결합하는 함수를 작성하고, 이전에 결합된 문자열을 기억하게 하세요.
function createStringCombiner() {
// 여기에 코드를 작성하세요
}
const combiner = createStringCombiner();
console.log(combiner("Hello")); // "Hello"
console.log(combiner(" World")); // "Hello World"
function createStringCombiner() {
let result = "";
return function (str) {
result += str;
return result;
};
}
const combiner = createStringCombiner();
console.log(combiner("Hello")); // "Hello"
console.log(combiner(" World")); // "Hello World"
설명: 객체의 속성 개수를 세는 함수를 작성하세요. 이 함수는 객체를 클로저로 기억해야 합니다.
function createPropertyCounter() {
// 여기에 코드를 작성하세요
}
const counter = createPropertyCounter();
console.log(counter({ a: 1, b: 2 })); // 2
console.log(counter({ a: 1 })); // 1
function createPropertyCounter() {
let count = 0;
return function (obj) {
for (let key in obj) {
// key를 실제로 사용하지 않음, 배운게 for...in문이라서 사용한 것임
// let _ in obj 로 표현해도 됨
count++;
}
return count;
};
}
const counter = createPropertyCounter();
console.log(counter({ a: 1, b: 2 })); // 2
console.log(counter({ a: 1 })); // 1
설명: 주어진 배열에서 특정 조건을 만족하는 요소만 필터링하는 함수를 작성하세요.
function createFilter(condition) {
// 여기에 코드를 작성하세요
}
const filterEven = createFilter(num => num % 2 === 0);
console.log(filterEven([1, 2, 3, 4, 5])); // [2, 4]
function createFilter() {
const result = [];
return function (array) {
for (let num of array) {
if (num % 2 === 0) result.push(num);
}
return result;
};
}
const filterEven = createFilter();
console.log(filterEven([1, 2, 3, 4, 5])); // [2, 4]
// 강사님 풀이
function createFilter(condition) {
return function (arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (condition(arr[i])) result.push(arr[i]);
}
return result;
};
}
let filterEven = createFilter((num) => num % 2 === 0);
console.log(filterEven([1, 2, 3, 4, 5])); // [2, 4]
설명: 여러 개의 카운터를 동시에 관리할 수 있는 함수를 작성하세요. 각 카운터는 별개의 값을 가지고 있어야 하며, 특정 카운터를 지정하여 그 카운터만 증가시키는 기능이 필요합니다.
function createMultiCounter() {
// 여기에 코드를 작성하세요
}
const counters = createMultiCounter();
const counterA = counters('A');
const counterB = counters('B');
console.log(counterA()); // 1
console.log(counterA()); // 2
console.log(counterB()); // 1
console.log(counterA()); // 3
console.log(counterB()); // 2
강사님 풀이
function createMultiCounter() {
const counts = {};
return function (label) {
if (!counts[label]) counts[label] = 0;
return function () {
counts[label]++;
return counts[label];
};
};
}
const counters = createMultiCounter();
const counterA = counters("A");
const counterB = counters("B");
console.log(counterA()); // 1
console.log(counterA()); // 2
console.log(counterB()); // 1
console.log(counterA()); // 3
console.log(counterB()); // 2
설명: 기본 연산을 수행할 수 있는 계산기를 작성하세요. 이 계산기는 특정 연산을 클로저로 기억하여 그 연산만 수행할 수 있도록 합니다.
function createCalculator(operator) {
// 여기에 코드를 작성하세요
}
const add = createCalculator((a, b) => a + b);
console.log(add(2, 3)); // 5
console.log(add(10, 5)); // 15
const multiply = createCalculator((a, b) => a * b);
console.log(multiply(2, 3)); // 6
console.log(multiply(10, 5)); // 50
강사님 풀이
function createCalculator(operator) {
return function (n1, n2) {
return operator(n1, n2);
};
}
const add = createCalculator((a, b) => a + b);
console.log(add(2, 3)); // 5
console.log(add(10, 5)); // 15
const multiply = createCalculator((a, b) => a * b);
console.log(multiply(2, 3)); // 6
console.log(multiply(10, 5)); // 50
오늘도 수업을 듣는 내내 따라가기 바빠서 뇌가 폭발하는 듯 했다.
항상 어렵지만 계속 고민하고 복습하면서 결국엔 하나 하나씩 이해를 해 나갈 때 마다 힘든 것보다
뿌듯한 게 더 크기 때문에 열심히 하고 버틸 수 있는 것 같다.
지금까지 정리해왔던 내용들을 티스토리에 다시 옮기기도 해야 하고,
문제도 다시 풀어봐야 해서 시간이 계속 부족하다.
주어진 시간은 한정적인데 할 게 너무 많은 느낌이라 조급한 마음이 자꾸 생긴다.
오늘은 함수 연습 문제 중 연습문제와 연습문제+를 다시 풀어봤다.
애너그램 문제에서 결국 막혀 버려서 답답해 하던 중 팀원들에게 도움을 청했고,
수빈님께서 아주 자세하게 설명해주셨다.
손이 닿지 않는 부분이 엄청 간지러웠는데 시워~~언하게 긁어주신 느낌.
a || b 에서 a가 true면 a, a가 false면 b를 다시 확인한다는 기본적인 걸 잊어버릴 줄
상상도 못했다.
나도 나름대로는 정말 세세하게 필기하고 메모한다고 생각했는데 수빈님이 코드 작성하시면서
메모하신 걸 보고는 정말 나름대로에 불과했구나라는 걸 느꼈다. 이래서 팀플이 중요한 건가...
다들 나보다 한참 어리지만 정말 실력들이 대단하고 멋지다.
나도 언젠가는 누군가에게 피드백도 해줄 수 있는 사람이 되길..