(SEB_FE) Section1 Unit9 클로저

PYM·2023년 3월 2일
0

(SEB_FE) SECTION1

목록 보기
32/38
post-thumbnail
  1. 클로저 함수의 정의와 특징에 대해서 이해할 수 있다.
  2. 클로저가 갖는 스코프 범위를 이해할 수 있다.
  3. 클로저를 이용해 유용하게 쓰이는 몇 가지 패턴을 이해할 수 있다.

⭐What is Closuer?

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). - mdn (2023)

➡ 클로저는 함수와 그 함수가 접근할 수 있는 변수의 조합

  • 클로저가 중요한 이유
    • 클로저의 함수는 어디에서 호출되느냐와 무관하게
      선언된 함수 주변 환경에 따라 접근할 수 있는 변수가 정해지기 때문에 중요하다!
// 클로저 사용 패턴 1
function outerFn() {
  const outerFnVar = 'outer 함수 내의 변수';
  const innerFn = function() { 
    return 'innerFn은 ' + outerFnVar + '에 접근할 수 있습니다.';
  }
	return innerFn;
}
  • 실제 클로저를 사용할 때는 outerFn, innerFn처럼 함수가 함수를 리턴하는 패턴을 자주 사용하고, outerFn외부 함수, innerFn내부 함수라고 부른다.
function outerFn() {
  const innerFn = function() { 
    const message = 'outerFn은 message에 접근할 수 있습니다.';
  }
	return message;
}
const message = outerFn();
  • 이 경우에는 outerFn은 ,message를 리턴하려고 하지만, innerFn의 스코프,
    내부 함수에 있기 때문에 접근할 수 없어, ReferenceError가 난다.

⭐클로저 활용

클로저를 응용하면, 함수 내부에 선언한 변수에 접근할 수 있고, 매개변수에도 접근할 수 있다

💫 데이터를 보존하는 함수

function createFoodRecipe (foodName) {
  let ingredient1 = '탄산수';
  let ingredient2 = '위스키';
  const getFoodRecipe = function () {
    return `${ingredient1} + ${ingredient2} = ${foodName}!`;
  }
  return getFoodRecipe;
}

const recipe = createFoodRecipe('하이볼');
recipe(); // '탄산수 + 위스키 = 하이볼!'

이 때, createFoodRecipe('하이볼') 으로 전달된 문자열 '하이볼'recipe 함수 호출 시 계속 재사용 할 수 있다.
➡ createFoodRecipe 가 문자열 ‘하이볼’ 을 “보존”하고 있기 때문

function createFoodRecipe (foodName) {
  const getFoodRecipe = function (ingredient1, ingredient2) {
    return `${ingredient1} + ${ingredient2} = ${foodName}!`;
  }
  return getFoodRecipe;
}

const highballRecipe = createFoodRecipe('하이볼');
highballRecipe('콜라', '위스키'); // '콜라 + 위스키 = 하이볼!'
highballRecipe('탄산수', '위스키'); // '탄산수 + 위스키 = 하이볼!'
highballRecipe('토닉워터', '연태고량주'); // '토닉워터 + 연태고량주 = 하이볼!'

highballRecipe 함수는 문자열 ‘하이볼’ 을 보존하고 있어서 전달인자를 추가로 전달할 필요가 없고, 다양한 하이볼 레시피를 하나의 함수로 제작할 수 있다

💫 커링

여러 전달인자를 가진 함수를 함수를 연속적으로 리턴하는 함수로 변경하는 행위

function sum(a, b) {
  return a + b;
}

function currySum(a) {
	return function(b) {
		return a + b;
	};
}

console.log(sum(10, 20) === currySum(10)(20)) // true
  • sumcurrySum이 같은 값을 리턴하기 위해서는 currySum 함수에서 리턴한 함수에 두 번째 전달인자 20을 전달하여 호출하면 된다.
  • 이렇게 커링을 활용한 currySum과 같은 함수를 커링 함수라고 부르기도 한다.
  • 커링 함수는 언뜻 봐서는 일반 함수와 그 차이가 느껴지지 않지만,
    ⬇️ 커링은 전체 프로세스의 일정 부분까지만 실행하는 경우 유용하다 ⬇️
function makePancake(powder) {
  return function (sugar) {
		return function (pan) {
			return `팬케이크 완성! 재료: ${powder}, ${sugar} 조리도구: ${pan}`;
		}
	}
}

const addSugar = makePancake('팬케이크가루');
const cookPancake = addSugar('백설탕');
const morningPancake = cookPancake('후라이팬');

// 잠깐 낮잠 자고 일어나서 ...
const lunchPancake = cookPancake('후라이팬');

//아래의 일반 함수는 위 커링 함수와 달리 
//잠깐 낮잠 자고 일어나서 만든 팬케이크를 표현할 방법이 없다.
function makePancakeAtOnce (powder, sugar, pan) {
  return `팬케이크 완성! 재료: ${powder}, ${sugar} 조리도구: ${pan}`;
}

const morningPancake = makePancakeAtOnce('팬케이크가루', '백설탕', '후라이팬')

✨이와 같이 커링은 함수의 일부만 호출하거나,
일부 프로세스가 완료된 상태를 저장하기에 용이하다!!✨

💫 모듈 패턴

  • JavaScript에 class 키워드가 없던 시절 모듈 패턴을 구현하기 위해서 클로저를 사용

  • 모듈이란?

    • 하나의 기능을 온전히 수행하기 위한 모든 코드를 가지고 있는 코드 모음으로, 하나의 단위로서 역할한다.

    • 모듈은 다른 모듈에 의존적이지 않고 독립적이어야 한다.
      즉, 기능 수행을 위한 모든 기능을 갖추고 있어야 하고, 외부 코드 실행을 통해서 모듈의 속성이 훼손 받지 않아야 한다는 것.

function makeCalculator() {
  let displayValue = 0;

  return {
    add: function(num) {
      displayValue = displayValue + num;
    },
    subtract: function(num) {
      displayValue = displayValue - num;
    },
    multiply: function(num) {
      displayValue = displayValue * num;
    },
    divide: function(num) {
      displayValue = displayValue / num;
    },
    reset: function() {
      displayValue = 0;
    },
    display: function() {
      return displayValue
    }
  }
}

const cal = makeCalculator();
cal.display(); // 0
cal.add(1);
cal.display(); // 1
console.log(displayValue) // ReferenceError: displayValue is not defined
  • displayValuemakeCalculator의 코드 블록 외에 다른 곳에서는 접근이 불가능하지만,cal의 메서드는 모두 클로저의 함수로서 displayValue에 접근 가능

  • 이렇게 데이터를 다른 코드 실행으로부터 보호하는 개념을 정보 은닉(information hiding)이라고 한다.
  • 이는 캡슐화(encapsulation)의 큰 특징!

  • ✨이와 같이 클로저는 특정 데이터를 다른 코드의 실행으로부터 보호할 때 용이!✨

근데 일단 모든 함수는 다 클로저이다.
주변 환경에 참조할 걸 가지고 있다면 일단 클로저(즉, 모든 함수)

그치만 '클로저'라는 개념을 주로 언급할때는,
외부함수 안에 내부함수가 있는 패턴일 때 사용한다.

즉, 실질적으로 코딩할 때 클로저를 활용하는 패턴이 외부 & 내부 함수 패턴


클로저는 대학생 수업과정에서는 배운 적 없는 개념이라 꽤 생소했다. 하지만 이런 유용한 개념을 모른채로 졸업 프로젝트를 만들었다니! 너무 아쉬웠다. 아직까지는 쉽게 쉽게 활용할 만큼 익숙한 개념은 아니지만, 얼른 연습문제 같은 것들은 많이 접하면서 익숙하게끔 해야겠다! 복습도 꾸준히 철저히 하기...!

profile
목표는 "함께 일하고 싶은, 함께 일해서 좋은" Front-end 개발자

0개의 댓글