화살표 함수 표현(arrow function expression)은 function 표현에 비해 구문이 짧고  자신의 this, arguments, super 또는 new.target을 바인딩 하지 않습니다. 화살표 함수는 항상 익명입니다. 이  함수 표현은 메소드 함수가 아닌 곳에 가장 적당합니다. 그래서 생성자로서 사용할 수 없습니다.

구문

기본 구문

(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
          // 다음과 동일함:  => { return expression; }

// 매개변수가 하나뿐인 경우 괄호는 선택사항:
(singleParam) => { statements }
singleParam => { statements }

// 매개변수가 없는 함수는 괄호가 필요:
() => { statements }

 

고급 구문

// 객체 리터럴 식을 반환하는 본문(body)을 괄호 속에 넣음:
params => ({foo: bar})

// 나머지 매개변수기본 매개변수가 지원됨
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements }

// 매개변수 목록 내 비구조화도 지원됨
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f();  // 6

상세한 구문 예는 여기에서 볼 수 있습니다.

설명

Hacks 블로그 "ES6 In Depth: Arrow functions" 포스트 참조.

화살표 함수 도입에 영향을 준 두 요소: 짧은 함수 및  바인딩하지 않은 this.

짧은 함수

일부 함수 패턴에서는, 짧은 함수가 환영받습니다. 비교해 보세요:

var materials = [
  'Hydrogen',
  'Helium',
  'Lithium',
  'Beryllium'
];

materials.map(function(material) { 
  return material.length; 
}); // [8, 6, 7, 9]

materials.map((material) => {
  return material.length;
}); // [8, 6, 7, 9]

materials.map(({length}) => length); // [8, 6, 7, 9]

 

바인딩 되지 않은 this

화살표 함수전까지는, 모든 새로운 함수는 자신의 this 값을 정의했습니다 (이 함수가 생성자인 경우는 새로운 객체, 엄격 모드 함수 호출에서는 undefined, 함수가 "객체 메서드"로서 호출된 경우 문맥 객체 등) . 이는 객체 지향 스타일로 프로그래밍할 때 별로 좋지않습니다.

function Person() {
  // Person() 생성자는 `this`를 자신의 인스턴스로 정의.
  this.age = 0;

  setInterval(function growUp() {
    // 비엄격 모드에서, growUp() 함수는 `this`를
    // 전역 객체로 정의하고, 이는 Person() 생성자에
    // 정의된 `this`와 다름.
    this.age++;
  }, 1000);
}

var p = new Person();

ECMAScript 3/5 에서는, 이 문제를 this 값을 폐쇄될 수 있는 (비전역) 변수에 할당하여 해결했습니다.

function Person() {
  var that = this;  
  that.age = 0;

  setInterval(function growUp() {
    // 콜백은  `that` 변수를 참조하고 이것은 값이 기대한 객체이다.
    that.age++;
  }, 1000);
}

이렇게 하는 대신에, 바인딩한 함수는 적절한 this 값이 growUp() 함수에 전달될 수 있도록 생성될 수 있습니다.

화살표 함수는 전역 컨텍스트에서 실행될 때 this를 새로 정의하지 않습니다. 대신 코드에서 바로 바깥의 함수(혹은 class)의 this값이 사용됩니다. 이것은 this를 클로저 값으로 처리하는 것과 같습니다. 따라서 다음 코드에서 setInterval에 전달 된 함수의 thissetInterval을 포함한 function의 this와 동일한 값을 갖습니다.

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this|는 person 객체를 '뙇' 하고 참조
  }, 1000);
}

var p = new Person();

엄격 모드와의 관계

this가 렉시컬(lexical, 정적)임을 감안하면, this에 관한 엄격 모드 규칙은 그냥 무시됩니다.

function Person() {
  this.age = 0;
  var closure = "123"
  setInterval(function growUp() {
    this.age++;
    console.log(closure)
  }, 1000);
}

var p = new Person();

function PersonX() {
  'use strict'
  this.age = 0;
  var closure = "123"
  setInterval(()=>{
    this.age++;
    console.log(closure)
  }, 1000);
}

var px = new PersonX();

엄격 모드의 나머지 규칙은 평소대로 적용합니다.

call 또는 apply를 통한 피호출

화살표 함수에서는 this가 바인딩되지 않았기 때문에, call() 또는 apply() 메서드는  인자만 전달 할 수 있습니다. this는 무시됩니다.

var adder = {
  base : 1,
    
  add : function(a) {
    var f = v => v + this.base;
    return f(a);
  },

  addThruCall: function(a) {
    var f = v => v + this.base;
    var b = {
      base : 2
    };

    return f.call(b, a);
  }
};

console.log(adder.add(1));         // 이는 2가 콘솔에 출력될 것임
console.log(adder.addThruCall(1)); // 이도 2가 콘솔에 출력될 것임

바인딩 되지 않은 arguments

화살표 함수는 arguments 객체를 바인드 하지 않습니다.  때문에, arguments는  그저 둘러싸는 범위(scope) 내 이름에 대한 참조입니다.

var arguments = [1, 2, 3];
var arr = () => arguments[0];

arr(); // 1

function foo(n) {
  var f = () => arguments[0] + n; // foo's implicit arguments binding. arguments[0] is n
  return f();
}

foo(1); // 2

화살표 함수는 자신의 arguments 객체가 없지만, 대부분의 경우에 나머지 매개변수가 좋은 대안입니다:

function foo(n) {
  var f = (...args) => args[0] + n;
  return f(2);
}

foo(1); // 3

메소드로 사용되는 화살표 함수

이야기 했듯이, 화살표 함수 표현은 메소드 함수가 아닌 형태로 사용 할 수 있습니다. 메소드로 사용하려고 한면 무슨일이 발생하는지 봅시다.

'use strict';

var obj = {
  i: 10,
  b: () => console.log(this.i, this),
  c: function() {
    console.log( this.i, this)
  }
}
obj.b(); // prints undefined, Window
obj.c(); // prints 10, Object {...}

화살표 함수는 자신의 this를 가지고("bind" 바인드)있지 않습니다.

Object.defineProperty()

 

'use strict';

var obj = {
  a: 10
};

Object.defineProperty(obj, 'b', {
  get: () => {
    console.log(this.a, typeof this.a, this); // undefined 'undefined' Window {...} (or the global object)
    return this.a + 10; // represents global object 'Window', therefore 'this.a' returns 'undefined'
  }
});

 

new 연산자 사용

화살표 함수는 생성자로서 사용될 수 없으며 new와 함께 사용하면 오류가 발생합니다.

 

var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor

 

yield 키워드 사용

yield 키워드는 화살표 함수의 본문(그 안에 더 중첩된 함수 내에서 허용한 경우를 제외하고)에 사용될 수 없습니다. 그 결과, 화살표 함수는 생성기(generator)로서 사용될 수 없습니다.

함수 본문

화살표 함수는 "concise 바디"든 보통 "block 바디"든 하나를 가질 수 있습니다.

concise바디는 중괄호'{}'로 묶이지않은 한줄짜리 바디이고 block바디는 중괄호로 묶인 바디입니다. 보통 여러줄 쓸때 block바디를 사용합니다.

block바디는 자동으로 값을 반환하지 않습니다. return을 사용해서 값을 반환해야 합니다.

var func = x => x * x;                  // concise 바디, 암시된 "return" 여기서는 x * x
var func = (x, y) => { return x + y; }; // block 바디, "return"이 필요

객체 리터럴 반환

간결한 구문 params => {object:literal}을 사용한 객체 리터럴 반환은 예상대로 작동하지 않음을 명심하세요:

var func = () => {  foo: 1  };               // func() 호출은 undefined를 반환!
var func = () => {  foo: function() {}  };   // SyntaxError: function 문은 이름이 필요함

이는 중괄호({}) 안 코드가 일련의 문(즉 foo는 라벨처럼 취급됩니다, 객체 리터럴 내 키가 아니라)으로 파싱(parse, 구문 분석)되기 때문입니다.

객체 리터럴를 괄호로 감싸는 것을 기억하세요:

var func = () => ({ foo: 1 });

줄바꿈

화살표 함수는  파라메터와 화살표 사이에 개행 문자를 포함 할 수 없습니다.

var func = ()
           => 1; 
// SyntaxError: expected expression, got '=>'

파싱순서

화살표 함수 내의 화살표는 연산자가 아닙니다. 그러나 화살표 함수는 평범한 함수와 비교했을 때 operator precedence와 다르게 반응하는 특별한 파싱룰을 가지고 있습니다.

let callback;

callback = callback || function() {}; // ok
callback = callback || () => {};      // SyntaxError: invalid arrow-function arguments
callback = callback || (() => {});    // ok

다른 예

//  empty 화살표 함수는 undefined를 반환 
let empty = () => {};

(() => 'foobar')(); 
// "foobar" 반환
// (this is an Immediately Invoked Function Expression 
// see 'IIFE' in glossary)

var simple = a => a > 15 ? 15 : a; 
simple(16); // 15
simple(10); // 10

let max = (a, b) => a > b ? a : b;

// Easy array filtering, mapping, ...

var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b); // 66
var even = arr.filter(v => v % 2 == 0); // [6, 0, 18]
var double = arr.map(v => v * 2); // [10, 12, 26, 0, 2, 36, 46]

// 더 간결한 promise 체인
promise.then(a => {
  // ...
}).then(b => {
  // ...
});

// Parameterless arrow functions that are visually easier to parse
setTimeout( () => {
  console.log('I happen sooner');
  setTimeout( () => {
    // deeper code
    console.log('I happen later');
  }, 1);
}, 1);

스펙

스펙 상태 설명
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Arrow Function Definitions' in that specification.
Standard 초기 정의.
ECMAScript Latest Draft (ECMA-262)
The definition of 'Arrow Function Definitions' in that specification.
Draft  

브라우저 호환성

 

FeatureChromeEdgeFirefoxInternet ExplorerOperaSafari
Basic support45 Yes221 2 No3210
Trailing comma in parameters58 ?52 No45 ?
FeatureAndroid webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
Basic support4545 Yes221 232105.0
Trailing comma in parameters5858 ?5245 ?7.0

1. The initial implementation of arrow functions in Firefox made them automatically strict. This has been changed as of Firefox 24. The use of 'use strict'; is now required.

2. Prior to Firefox 39, a line terminator (\n) was incorrectly allowed after arrow function arguments. This has been fixed to conform to the ES2015 specification and code like () \n => {} will now throw a SyntaxError in this and later versions.

 

참조

문서 태그 및 공헌자

최종 변경: limkukhyun,