화살표 함수(Arrow Function)

화살표 함수는 function 대신 =>를 사용함으로써 좀 더 간결하게 함수를 선언할 수 있다.

또한 화살표 함수는 익명 함수로만 사용할 수 있기 때문에 함수 표현식을 사용한다.

const foo = () => {...} //매개변수가 없을 때
const foo = x => {...} //매개변수가 하나일 때
const foo = (x, y) => {...} //매개변수가 여러 개일 때

const foo = x => { return x; }
const foo = x => x; // 함수의 블록이 한줄이라면 중괄호와 return을 생략

const sum = (x, y) => {
    return x + y;
}

console.log(sum(1, 2)); //3
//ES5
var arr = ["JS", "Java", "Go"];
var foo = arr.map(function(element) {
  return { Lang: element };
});

console.log(foo); //[{Lang: "JS"}, {Lang: "Java"}, {Lang: "Go"}]

//ES6
const arr = ["JS", "Java", "Go"];
const foo = arr.map(element => {
  return { Lang: element };
});

console.log(foo); //[{Lang: "JS"}, {Lang: "Java"}, {Lang: "Go"}]

화살표 함수에서의 this 바인딩

ES5에서는 함수의 호출 방식에 따라 this가 동적으로 바인딩이 이뤄진다.

ES5의 this 바인

하지만 화살표 함수에서는 this가 무조건 상위 스코프의 this를 가리킨다.

즉 정적인 방식으로 this가 바인딩이 되는데 이를 Lexical this 라고 한다.

위의 소스를 화살표 함수를 이용해서 바꾸면 var that = this;라는 구문을 쓸 필요가 없다.

const lang = "Korean";

const obj = {
  lang: "English",
  outerFunc() {
    //ES6의 축약 메서드 표현
    console.log("outerFunc : ", this.lang);

    innerFunc1 = () => {
      console.log("innerFunc1 : ", this.lang);

      innerFunc2 = () => {
        console.log("innerFunc2 : ", this.lang);
      };

      innerFunc2();
    };

    innerFunc1();
  }
};

obj.outerFunc();

/*
outerFunc : English
innerFunc1 : English
innerFunc2 : Engilsh
*/

항상 화살표 함수일까?

화살표 함수는 위에서 본 것 처럼 정적으로 this를 바인딩(Lexical this)를 지원하기 때문에 콜백 함수로 쓰기 매우 편하다. 하지만, 주의해서 써야할 경우가 몇 가지 있다.

addEventListener의 콜백 함수 선언

const btn = document.getElementById("submitBtn");

btn.addEventListener("click", () => {
  console.log(this); //Window
});

위에서 볼 수 있듯이 addEventListener콜백 함수를 화살표 함수로 선언하면 thiswindow에 바인딩되므로 그냥 일반함수를 사용하여 선언하여야 한다.

객체의 메서드에 선언

객체의 메서드를 선언할 때, 화살표 함수를 쓰면 그 객체에 this가 바인딩되지 않고 전역(window)에 바인딩된다.

var lang = "Korean";

const obj = {
  lang: "English",
  foo: () => {
    console.log("outerFunc : ", this.lang);
  }
};

obj.foo(); //outerFunc : Korean

위에선 English가 나온다고 생각할 수도 있다.
하지만, foo 선언할 때 화살표 함수를 사용했고 이에 따라 상위 컨텍스트인 windowthis가 바인딩 되기 때문에 결과는 Korean이 나온다.

따라서 원하는 결과가 English라면 축약 메서드 표현법으로 정의하는 것이 맞다.

var lang = "Korean";

const obj = {
  lang: "English",
  foo() {
    console.log("outerFunc : ", this.lang);
  }
};

obj.foo(); //outerFunc : English

프로토타입 객체의 메서드 선언

프로토타입 객체에 메서드를 화살표 함수로 정의하면 객체의 메서드에 화살표 함수로 선언할 때와 같이 thiswindow에 바인딩된다.

const devleoper = {
  name: "BKJang"
};

Object.prototype.renderData = () => console.log(this.name);

devleoper.renderData(); //undefined

생성자 함수 선언

결론부터 말하면, 화살표 함수는 prototype 프로퍼티를 갖고 있지 않다. 따라서 생성자 함수를 선언할 때 화살표 함수를 쓰면 인스턴스를 생성할 수 없다.

const Person = name => {
  this.name = name;
};

const jang = new Person("BKJang"); //Uncaught TypeError: Person is not a constructor