Open wonsss opened 2 years ago
함수 A
에서 선언한 변수 a
를 참조하는 내부함수 B
를 외부로 전달할 경우, 함수 A
의 실행 컨텍스트가 종료된 이후에도 변수 a
가 사라지지 않는 현상이다.
메모리 소모
에 대한 관리법만 잘 파악해서 적용하면 충분하다.let outer = (function () {
let a = 1;
let inner = function () {
return ++a;
};
return inner;
})();
console.log(outer());
console.log(outer());
outer = null; // outer 식별자의 inner 함수 참조를 끊는다.
// setInterval
(function () {
let a = 0;
let intervalId = null;
let inner = function () {
if (++a >= 10) {
clearInterval(intervalId);
inner = null; // inner 식별자의 함수 참조 끊기
}
console.log(a);
};
intervalId = setInterval(inner, 1000);
})();
const add = function () {
let result = 0;
for (let i = 0; i < arguments.length; i++) {
result += arguments[i];
}
return result;
};
const addPartial = add.bind(null, 1, 2, 3, 4, 5);
console.log(addPartial(6, 7, 8, 9, 10)); // 55
커링 함수란 여러 개의 인자를 받는 함수를 하나의 인자만 받는 함수로 나눠서 순차적으로 호출할 수 있게 체인형태로 구성한 것을 말한다.
Currying 은 1967년 Christopher Strachey 가 Haskell Brooks Curry의 이름에서 착안한 것이다. Currying은 여러 개의 인자를 가진 함수를 호출 할 경우, 파라미터의 수보다 적은 수의 파라미터를 인자로 받으면 누락된 파라미터를 인자로 받는 기법을 말한다. 즉 커링은 함수 하나가 n개의 인자를 받는 과정을 n개의 함수로 각각의 인자를 받도록 하는 것이다. 부분적으로 적용된 함수를 체인으로 계속 생성해 결과적으로 값을 처리하도록 하는 것이 그 본질이다. Haskell 및 Scala와 같은 언어는 currying이 기본적으로 내장되어 있지만, 자바스크립트는 커링이 내장되어 있지 않다. 하지만 자바스크립트도 커링을 구현할 수 있다.
const curry3 = function (func) {
return function (a) {
return function (b) {
return func(a, b);
};
};
};
const getMaxWith10 = curry3(Math.max)(10);
console.log(getMaxWith10(8)); // 10
curry3 매개변수로
인자가 많아질수록 가독성이 떨어질 수 있긴 하나, 화살표 함수를 쓰면 한 줄에 표기할 수 있다.
const curry5 = func => a => b => c => d => e => func(a, b, c, d, e);
console.log(curry5(Math.max)(1)(2)(3)(4)(5)); // 5
지연실행
이라고 칭한다.
const getInformation = function (baseUrl) {
return function (path) {
return function (id) {
return fetch(baseUrl + path + "/" + id);
};
};
};
// 화살표 함수 버전
const getInformation = baseUrl => path => id =>
fetch(baseUrl + path + "/" + id);
그냥
발생한다.
함수가 속한 렉시컬 스코프
를 기억하여 함수가 렉시컬 스코프 밖에서
실행될 때에도 이 스코프에 접근
할 수 있게 하는 기능을 뜻한다.function foo() {
const a = 2;
function bar() {
// bar()함수는 foo()의 렉시컬 스코프에 접근할 수 있다.
console.log(a);
}
return bar; // bar()함수 자체를 값으로 반환한다.
}
const baz = foo(); // foo()를 실행하여 반환된 값(bar()함수)을 baz 변수에 대입
baz(); // baz()함수 호출 -> 대입되어 있는 bar()함수가 호출된다.
// 이 경우 함수 bar()는 함수가 선언된 렉시컬 스코프 밖에서 실행됐다.
사용 중
이므로 해제되지 않는다
.
참조
를 클로저
라고 한다.함수를 값으로 넘겨
다른 위치에서 호출
하는 행위는 모두 클로저가 작용한 예다.for (var i = 1; i <= 5; i++) {
// var 임을 주의
setTimeout(function timer() {
console.log(i); // 6 6 6 6 6
}, i * 1000);
}
위 코드는, 반복문 안 총 5개의 함수들은 반복마다 따로 정의됐음에도 모두 같은 글로벌 스코프 클로저를 공유하게 되어, 해당 스코프 안에는 오직 하나의 i(=6)만이존재한다. 따라서 모든 함수는 같은 i에 대한 참조를 공유한다.
이를 해결하기 위해, 반복마다 i의 값을 저장할 변수를 IIFE 안에 선언하고 할당한다. 즉, 필요한 것은 반복 별 블록 스코프다.
for (var i = 1; i <= 5; i++) {
(function () {
var j = i;
setTimeout(function timer() {
console.log(j); // 1, 2, 3, 4, 5
}, j * 1000);
})();
}
반복할 때마다
선언된다. 따라서 해당 변수는 반복마다 이전 반복이 끝난 이후의 값으로 초기화된다.for (let i = 1; i <= 5; i++) {
// let으로 변경됨
setTimeout(function timer() {
console.log(i); // 1 2 3 4 5
}, i * 1000);
}
Closure