wonsss / vanila-js-wiki

1 stars 0 forks source link

Closure #3

Open wonsss opened 2 years ago

wonsss commented 2 years ago

Closure

wonsss commented 2 years ago

클로저

클로저와 메모리 관리

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);
})();

2. 클로저 활용 사례

(1) 콜백 함수 내부에서 외부 데이터를 사용하고자 할 때

(2) 접근 권한 제어(정보 은닉)

(3) 부분 적용 함수

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

(4) 커링 함수

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
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);
wonsss commented 2 years ago

스코프 클로저

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);
}