- Published on
ES6) Arrow Function (화살표 함수)
- Authors
- Name
- Hoehyeon Jung
1. Arrow Function
ES6에 들어서면서 JS 스펙에서 함수를 선언하는 새로운 방법으로 화살표 함수(Arrow Function)이 추가되었다. 화살표 함수는 함수를 선언하는 방식이 기존보다 간결해졌을 뿐만 아니라 일반 함수 선언방식과 차이를 가지는 만큼 이러한 차이를 정확히 인지하고 사용해야 한다.
1-1. 화살표 함수 선언
// paremeter 선언 방식
// ES5
function hiDeprecated (firstName, lastName) {
console.log('Hi, ' + firstName + ' ' + lastName );
}
// -- ES6 --
// paremeter 개수 별 0개, 1개, 2개 이상의 경우
const getUnixTime = () => { return new Date().getTime() }
const doubleInt = value => { return value * 2 };
const sayHello = (firstName, lastName) => {
console.log(`Hi, ${firstName} ${lastName}`);
}
기본적인 선언 방식은 위와 같다. 매개변수가 없으면 빈 괄호를, 1개의 경우는 괄호를 생략할 수 있으며 2개 이상의 경우에는 괄호 안에 매개 변수를 차례대로 입력하면 된다. 기본적으로 화살표 함수는 익명함수로 선언하기 때문에 위와 같이 함수 표현식으로 선언하게 된다.
// 함수 블록 설정
// ES5
var discountedPriceDeprecated = function (ratio, price) {
return ratio * price;
}
// -- ES6 --
const getDiscountedPrice = (ratio, price) => ratio * price;
const getNameAndAgeFromUser = user => ({ name: user.name, age: user.age })
또한 함수 블록 지정에 있어서도 위와 같이 한줄로 선언되는 경우 중괄호와 return을 생략하고 간결하게 표현할 수 있다. 다만 객체를 반환하는 경우 함수 블록과의 구분을 위해 객체를 소괄호()로 감싸야 한다.
// 매개 변수로 선언
// ES5
var getAdultDeprecated = function (user) {
var result = [];
user.forEach(function (value) {
if (value.age > 20) {
result.push[value];
}
});
return result;
}
// ES6
const getAdultUser = user => user.filter(x => x.age > 19);
javascript의 함수는 일급 시민(first citizen)의 속성을 가지고 있기 때문에 매개변수로 변수들만 들어가는 것이 아닌 함수 자체가 들어갈 수 있다. 이러한 특성을 이용해 함수를 적절하게 합성하여 프로그래밍하는 것이 가능하다. 또한 이러한 매개변수나 콜백함수로 들어가는 함수들도 화살표 함수를 통해 간결하게 표현이 가능하다. 위의 예제의 경우 filter라는 고차함수로 내부의 화살표 함수의 조건을 만족하는 배열만 통과하는 함수이다.
1-2. 화살표 함수 호출
// ES6
const userList = [
{name: 'kim', age: 25},
{name: 'lee', age: 17}
]
const adults = getAdultUser(userList);
console.log(adults); // [{name: 'kim', age: 25}]
이렇게 익명함수로 선언된 화살표 함수들을 호출하기 위해서는 호출할 때 선언한 변수로 선언이 가능하다.
1-3. this
화살표 함수를 구사함에 있어서 가장 주의해야 할 것이 이 this가 가르키는 것이 이전의 선언 방식과 차이를 가지는 것이다.
1-3-1. 일반 함수의 this
function User(name) {
this.name = name;
this.location = ['home', 'company']
}
// this.location = User.location, this.name = window.name
User.prototype.locationWithName = function () {
return this.location.map(function(x) {return this.name + '\'s ' + x});
}
// this.location = User.location, this.name = User.name
User.prototype.locationWithBindedName = function () {
return this.location.map(function(x) {return this.name + '\'s ' + x}.bind(this));
}
var kim = new User('kim');
console.log(kim.locationWithName());
console.log(kim.locationWithBindedName());
일반적인 함수 선언 시, 생성자 함수나 객체의 메서드가 아닐 경우에는 내부함수의 this는 전역객체 window를 가리킨다. 위의 예제에서도 내부 함수의 this의 경우에는 전역객체 window를 바라보고 name을 찾기 때문에 엉뚱한 값이 나온다. 이를 해결하기 위한 해결책으로 다양한 방법이 있지만 bind를 통해서 현재 객체의 this를 바라보게 할 수 있다.
1-3-2. 화살표 함수의 this
function User(name) {
this.name = name;
this.location = ['home', 'company']
}
// this.location = User.location, this.name = User.name
User.prototype.locationWithName = function () {
return this.location.map(x => `${this.name}'s ${x}`);
}
var kim = new User('kim');
console.log(kim.locationWithName());
화살표 함수의 경우 선언 시, 일반 함수에서 bind를 통해 상위 객체의 this를 바라보게 하는 작업을 수행한다. 이를 lexical this라고 한다. 이러한 차이 때문에 this를 사용할 때는 특히 더 유의해야 한다. 객체의 메서드나 prototype 선언 시 this가 내부에서 사용된 경우는 일반 함수를 쓰는 것이 바람직하다.
1-4. 화살표 함수를 사용하지 말아야 할 경우
화살표 함수는 일반함수와의 차이로 인해 문제가 발생할 수 있다.
1-4-1. 생성자 함수 생성
const User = name => {this.name = name};
// false
console.log(User.hasOwnProperty('prototype'));
// error
const kim = new User('kim');
생성자 함수는 prototype 속성을 가지고, prototype이 가리키는 프로토타입 객체의 constructor를 사용한다. 하지만 화살표 함수는 prototype 속성이 없으므로 생성자 함수로 사용할 수 없다.
1-4-2.addEventListener 함수의 콜백함수
const button = document.querySelector('#myButton');
button.addEventListener('click', () => {
// true
console.log(this === window);
this.innerHTML = 'Clicked';
});
addEventListener 함수의 경우 this가 window를 가리키므로 버튼 내부에서 기리키는 this가 전역 객체 window를 가르키게 된다. 따라서 버튼의 이름이 아니게 되는 문제가 발생할 수 있으므로 이러한 경우에는 일반함수를 사용하는 것이 낫다.