TIL - 2022.11.08

흔한 감자·2022년 11월 8일
0

코드스테이츠

목록 보기
8/18

클로저

클로저는 함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다.
MDN - 클로저

조금 다르게 설명하면 외부 함수의 변수에 접근할 수 있는 내부 함수라고 할 수도 있습니다.

let sum = function(x) {
  let add = function(y) {
    return x + y;
  }
  return add;
}

let result = sum(10);
console.log(result(3)); // 13
console.log(result(5)); // 15

위 예제처럼 클로저는 내부 함수인 add에서 y 변수 뿐만 아니라 외부 함수의 파라미터인 x 변수에 접근하여 사용이 가능합니다. 이러한 것이 가능하는 이유는 자바스크립트는 렉시컬 스코프를 따르는 언어이기 때문이빈다.

렉시컬 스코프

어디서 호출했는지가 아닌 함수를 어디서 정의했는지에 따라 상위 스코프가 정해지는 것을 렉시컬 스코프(또는 정적 스코프)라고 말하다
출처: 모던 자바스크립트 Deep Dive

const x = 20;

function sum() {
  const x = 100;
  add();
}

function add() {
  console.log(x + 10);
}

sum();   //30
add();   //30

렉시컬 스코프를 따르기 떄문에 정의 시점으로 살펴보았을때 sum()add() 상위 스코프는 적역이 된다. 그렇기 때문에 sum() 내부 변수인 xadd()x에 영향을 주지 못한다.

이를 가능하기 위해서 자바스크립트에서는 내부 슬롯인 [[Environment]]에 자신의 상위 스코프의 참조를 저장합니다.

클로저로 판단되지? 않는 경우들...

클로저를 사용하는 것처럼 보이지만, 클로저의 특징을 활용하지 못하는 케이스가 있습니다.

상위 스코프의 식별자를 참조하지 않는 경우

function sum() {
  const x = 100;
  
  function add() {
    const y = 10;
    console.log(y + 10);
  }
  return add;
}

const add = sum();
add();

위의 경우 클로저라고 생각할 수도 있지만, 대부분의 브라우저에서 최적화를 하는 과정에서 상의 스코프의 어떠한 식별자도 참조하지 않는 경우 상위 스코프의 참조를 저장하지 않는다. 그렇기 때문에 클로저라고 부를 수 없다.

함수를 반환하지 않는 경우

function sum() {
  const x = 100;
  
  function add() {
    console.log(x + 10);
  }
  add();
}

const add = sum();

클로저의 경우 일반적으로 외부 함수(상위 함수)보다 내부 함수의 생명주기가 긴게 일반적입니다. 하지만 위의 경우 add 함수가 sum이 종료시점에 이미 반환되어 수행종료되었기 때문에 생명주기 더 짧기 때문에 클로저에 부합하지 않습니다.

클로저 커링

커링은 여러 인수 를 취하는 함수를 각각 단일 인수를 취하는 일련의 함수로 변환 하는 기술을 말한다.
출처 : 위키피디아 - 커링

function add(x) {
  return function(y) {
    return x + y;
  }
}

let add3 = add(3);   

console.log(add3(5)); //3 + 5 => 8
console.log(add3(2)); //3 + 2 => 5

커링을 사용하면 특정인자를 고정하여 재사용할 수 있다는 장점이 있습니다.

클로저와 모듈패턴

자바스크립트에서 모듈패턴은 클로저 기반으로 즉시 실행 함수로 함수와 변수를 감싸 만든 것을 말합니다. 이를 통해 클래스와 비슷한 구조를 가지게 됩니다.
(참고로 자바스크립트에 클래스가 존재하지만, 추후에 공부 후 다루도록 하겠습니다...)

클로저 모듈 패턴 구현

var counter = (function () {
  var privateCounter = 0;

  return {
    increment: function () {
      ++privateCounter;
    },
    decrement: function () {
      --privateCounter;
    },
    getCounter: function () {
      return privateCounter;
    },
  };
})();

자바스크립트에는 다른 언어와 다르게 접근 제한 키워드인 public, private, protected 등이 존재 하지 않는다. 하지만 클로저를 통한 모듈 패턴을 적용하면 접근 제한자를 사용할때와 비슷한 효과를 볼 수 있어 캡슐화은닉화가 가능해진다.

단점

클로저는 상위 스코프 함수를 내부 함수가 언제든 접근 할 수 있도록 메모리에 남아 있습니다. 그렇기 때문에 클로저를 남발할 경우 성능 저하가 발생할 수도 있습니다.


spread, rest 문법

  1. 병합
const arr = [1, 2, 3];
const arr2 = [4, 5, 6];

const mergeArr = [...arr, ...arr2];
console.log(mergeArr); //[1, 2, 3, 4, 5, 6]

const obj = { x: 10, y: 20 };
const obj2 = { z: 30, d: 40 };

const mergeObj = {...obj, ...obj2};
console.log(mergeObj); //{ x: 10, y: 20, z: 30, d: 40 }
  1. 복사
const arr = [1, 2, 3];
const copyArr = [...arr];

const obj = [1, 2, 3];
const copyObj = {...obj};
  1. Rest 파라미터
    스프레드 문법을 통해 나머지 파리미터를 모두 받아 올 수 있습니다. array 형태로 담겨져온다.
function func(a, ...args) {
  console.log(args);
}

func("1", "2", "3", "4", "5");
//["2", "3", "4", "5"]

구조 분해 할당

구조 분해 할당은 배열 또는 객체를 해체후 새로운 변수에 할당 과정을 말합니다.

const [a, b, ...rest] = [1, 2, 3, 4];

console.log(a); // 1
console.log(b); // 2
console.log(rest); //[3, 4]

const {name, age, ...restObj} = {
  name: 'jungsu',
  age: 31,
  phone: '010-1111-111',
  company: 'macom',
};

console.log(name); // jungsu
console.log(age); // 31
console.log(restObj); //{phone: '010-1111-111', company: 'macom'}
profile
프론트엔드 개발자

0개의 댓글