클로저는 함수가 생성되는 시점에 접근 가능했던 변수들을 생성 이후에도 계속해서 접근할 수 있게 해주는 기능이다. 접근할 수 있는 변수는 그 함수를 감싸고 있는 상위 함수들의 매개변수와 내부 변수들이다.

 

클로저를 사용한 간단한 코드

function makeAddFunc(x) {
  return function add(y) {
    return x+y;
  }
}
const add5 = makeAddFunc(5);
console.log(add5(1)); // 6

const add7 = makeAddFunc(7);
console.log(add7(1)); //8
console.log(add5(1)); //6

add 함수는 상위 함수인 makeAddFunc의 매개변수 x에 접근할 수 있다. add5 함수가 생성된 이후에도 상위 함수를 호출할 때 사용했던 인수에 접근할 수 있다. 중간에 makeAddFunc(7)이 호출되지만 add5에 영향을 주지는 않는다. 즉, 생성된 add 함수별로 클로저 환경이 생성된다.

 

 

ES6+ 에서는 화살표 함수를 이용해 함수를 정의하는 방법이 추가되었다. 화살표 함수를 사용하면 함수를 정말 간결하게 작성할 수 있다.

const add = (a,b) => a+b;

이런식으로 사용되는데 화살표 함수를 중괄호로 감싸지 않으면 오른쪽의 계산 결과가 반환된다. 

const add = a => a+b;

 

매개변수가 하나라면 매개변수를 감싸는 소괄호도 생략 있다.

const addAndReturnObject = (a,b) => ({return: a+b})

객체를 반환해야 한다면 소괄호로 감싸야 한다.

 

화살표 함수의 코드가 여러줄인 경우

const add = (a,b) => {
  if(a <0 || b<= 0) {
    throw new Error('must be position number');
  }
  return a+b;
}

화살표 함수에 여러 줄의 코드가 필요하다면 이와 같이 전체를 중괄호로 묶고 반환값에는 return이라는 키워드를 사용함 된다.

그리고 ES6는 this 바인딩 때문에 버그가 발생하는 경우 화살표 함수를 사용하면 그 버그를 제어할 수 있다.

function Something() {
  this.value = 1;
  this.increase = () => this.value++;
}

const obj = new Something();
obj.increase();
console.log(obj.value);

const increase = obj.increase;
increase();
console.log(obj.value);

화살표 함수의 increase의 this는 가장 가까운 일반 함수인 Something의 this를 참조한다. Something 함수는 생성자이고 밑에 obj 객체가 생성될 때 호출된다. new 키워드를 이용해서 생성자 함수를 호출하면 this는 생성되는 객체를 참조한다는 점에 유의하자. increase함수의 this는 생성된 객체를 가르킨다. 그러니 호출되는 시점의 객체와는 무관하게 increase함수의 this는 항상 생성된 객체를 참조하고 obj.value는 계속 증가한다.

 

비구조화 심화 학습

비구조화는 객체와 배열이 중첩되어 있을 때도 사용할 수 있다.
const obj = {name: 'mike', mother: {name: 'sara'}};
const {
  name,
  mother: {name : motherName},
} = obj;

console.log(name);
console.log(motherName);
console.log(mother);

이 처럼 세개의 단어가 등장하지만, 비구조화 결과로 motherName이라는 변수만 생성된다. 비구조화에서 기본값의 정의는 변수로 한정되지 않는다.

 

객체비구조화

const index = 1;
const { [`key${index}`]: valueOfTheIndex} = {key1: 123};
console.log(valueOfTheIndex); //123

객체 비구조화에서 계산된 속성명을 사용할 때에는 반드시 별칭을 입력해야한다. 별칭은 단순히 변수명만 입력할 수 있는 것은 아니다.

({foo: obj.prop, bar: arr[0]} = {foo : 123, bar: true});
console.log(obj); // {prop:123}
console.log(arr); // [true]

첫 줄처럼 객체 비구조화를 이용해서 obj 객체의 prop이라는 속성과 배열의 첫 번째 원소에 값을 할당하고 있다.

 

강화된 ES6+ 함수의 기능 

매개변수에 기본값을 줄 수 있게 되었고, 나머지 매개변수를 통해 가변 길이 매개변수를 좀 더 명시적으로 표현할 수 있게 되었다. 명명된 매개변수를 통해 함수를 호출하는 코드의 가독성이 월등히 좋아졌다. 그리고 화살표 함수가 추가되면서 함수 코드가 간결해졌고, this 바인딩에 대한 고민을 덜 수 있게 되었다.

 

매개변수의 추가된 기능

1. 매개변수 기본값 : ES6부터 함수 매개변수에 기본값을 줄 수 있다. 
function printLog(a=1) {
  console.log({a});

}
printLog(); // {a:1}

인수 없이 함수를 호출하므로 a에는 undefined가 입력됨 ! 기본값이 정의된 매개변수에 undefined를 입력하면 정의된 기본값이 1이 사용된다. 객체 비구조화처럼 기본값으로 함수 호출을 넣을 수 있고, 기본값이 필요한 경우에만 함수가 호출된다.

 

2. 나머지 매개변수 : 나머지 매개변수는 입력된 인수 중에서 정의된 매개변수 개수만큼 제외한 나머지를 배열로 만들어 준다. 나머지 매개변수는 매개변수 개수가 가변적일 때 유용하다.
function printLog(a, ...rest) {
  console.log({a, rest});
}

printLog(1,2,3); // {a:1, rest:[2,3]}

하나의 인자를 제외한 나머지 rest 매개변수에 할당한다. ES5에서는 arguments 키워드가 비슷한 역할을 한다. 

 

3. 명명된 매개변수 : 자바스크립트에서 명명된 매개변수는 객체 비구조화를 이용해서 구현할 수 있다.
명명된 매개변수를 사용하면 함수 호출 시 매개변수의 이름과 값을 동시에 적을 수 있으므로 가독성이 높다.
그리고 명명된 매개변수를 사용하면 함수를 호출할 때마다 객체가 생성되기 때문에 비효율적일 것이라고 생각할 수 있다. 하지만 자바스크립트 엔진이 최적화를 통해 새로운 객체를 생성하지 않으므로 안심하고 사용해도 된다.
const numbers = [10,20,30,40];
const result1 = getValues(numbers, 5, 25);
const result2 = getValues({ numbers, greaterThan:5, lessThan:25});// << 이렇게 매개변수의 이름과 값을 동시에 적을 수 있어서 가독성이 좋아졌다.

 

+ Recent posts