화살표 함수(Arrow Function)은 ES6에 추가된 것으로, 기존 일반 함수 표현보다 짧은 구문으로 가독성 높은 코드를 작성할 수 있게 도와줍니다.
[일반 함수 선언]
기존 일반 함수(regular function) 선언은 다음과 같이 'function'을 이용해서 구성됩니다.
var sum = function(a, b){
return a + b;
};
[화살표 함수 선언]
ES6에 추가된 화살표 함수 표기법을 이용하면 아래와 같은 코드로 위와 동일한 기능을 표현할 수 있습니다.
var sum = (a, b) => {
return a + b;
};
처음에는 약간 어색할 수 있는데, 사용하다 보면 코드의 가독성이 높아집니다.
특히 callback 함수로 사용할 때 그 효과가 큰 것 같습니다.
만약 argument에 1개의 파라미터만 있는 경우에는 파라미터의 괄호를 생략할 수 있습니다.
var greeting = (hello) => {
return hello + ' world';
};
// 축약형
var greeting = hello => {
return hello + ' world';
};
화살표 함수에는 반환 구문을 단축하는 방법도 내장되어 있스빈다.
화살표 함수가 반환(return)코드로만 구현되어 있는 겨웅, 괄호와 return 키워드를 생략할 수 있습니다.
var sum (a, b) => { return a + b; };
// 축약형
var sum (a, b) => a + b;
this 관련 글에서 함수를 선언할 때 this에 바인딩할 객체가 결정되는 것이 아니고, 함수를 어떻게 호출하느냐에 따라서 this가 가리키는 객체가 결정되는 것을 확인했습니다.
하지만 화살표 함수의 경우는 이와 다릅니다.
화살표 함수를 사용하는 경우에는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정됩니다.
화사료 함수는 this에 대한 binding이 없으며 화살표 함수가 정의되어 있는 객체의 스코프를 그대로 가지고 있습니다.
따라서 화살표 함수 내의 this는 상위 스코프의 this를 의미 합니다.
여기 제일 예쁜 사람을 알려주는 거울(newMirror)이 있습니다.
마법거울이 살아남기 위해서는 magicMirror 객체 안의 프로퍼티 sejelye를 참조해서 대답해야 합니다.
그런데 거울이 대답하는 부분(console.log)은 객체 안의 메서드로 실행되는 것이 아니라 setTimeout을 이용하여 내부 함수로 실행되고 있습니다.
this 관련 글에서 내부 함수의 경우, this는 기본적으로 전역 객체(window)를 가리킵니다.
따라서 ①의 경우 sejely는 백설공주를 나타내게 되는거죠.
어떻게 하면 내부 함수로 호출되면서 magicMirror안의 프로퍼티 sejelye를 불러올 수 있을까요?
var sejelye = '백설공주';
var magicMirror = {
sejelye: '여왕님',
// 1. 일반 함수
reply: function() {
setTimeout(function() {
console.log(`일반 거울 : 세상에서 제일 예쁜 사람은 ${this.sejelye}입니다.`);
}, 1000);
},
// 2. setTimeout에 this argument 추가
reply_arg: function() {
setTimeout(function(that) {
console.log(`thisArg 거울 : 세상에서 제일 예쁜 사람은 ${that.sejelye}입니다.`);
}, 2000, this);
},
// 3. that = this
reply_that: function() {
var that = this;
setTimeout(function() {
console.log(`that 거울 : 세상에서 제일 예쁜 사람은 ${that.sejelye}입니다.`);
}, 3000);
},
// 4. bind 사용
reply_bind: function() {
setTimeout((function() {
console.log(`바인딩된 거울 : 세상에서 제일 예쁜 사람은 ${this.sejelye}입니다.`);
}).bind(this), 4000);
},
// 5. arrow function 사용
reply_arrow: function() {
setTimeout(() => {
console.log(`화살표 거울 : 세상에서 제일 예쁜 사람은 ${this.sejelye}입니다.`);
}, 5000);
}
};
setTimeout(() => {
console.log("Queen: 거울아 거울아, 세상에서 누가 제일 예쁘니?\n\n");
}, 0);
magicMirror.reply(); // 세상에서 제일 예쁜 사람은 백설공주입니다.
magicMirror.reply_arg(); // 세상에서 제일 예쁜 사람은 여왕님입니다.
magicMirror.reply_that(); // 세상에서 제일 예쁜 사람은 여왕님입니다.
magicMirror.reply_bind(); // 세상에서 제일 예쁜 사람은 여왕님입니다.
magicMirror.reply_arrow(); // 세상에서 제일 예쁜 사람은 여왕님입니다.
② setTimeOut에 this argument를 추가
setTimeOut에서는 parameter로 callback 함수에 인자를 주입할 수 있습니다.
this(=magicMirror)를 인자로 제공하고 내부 함수에서 that으로 받아서 사용합니다.
③ var that = this
객체의 this를 that이란 변수에 넣어두고 내부 함수에서 this 대신 that을 이용합니다. 이 경우가 일반적으로 널리 사용되어 왔던 방식입니다.
④ bind 이용
bind를 이용하여 this를 내부 함수에 주입해줍니다.
※ ⑤ 화살표 함수를 사용
위에서 ② ~ ④의 방식들은 무언가 하나씩 해주었습니다만, 화살표 함수의 경우에는 별다른 조치를 취하지 않았습니다.
그 이유는 앞에 설명한 대로 화살표 함수에서의 this는 상위 스코프의 this를 의미하기 때문입니다.
내부 함수 상위 스코프의 this는 magicMirror를 참조하기 때문에 별 다른 처리 없이 '여왕님'으로 제대로 대답을 해줄 수 있습니다.
한 가지 중요한 점은 화살표 함수의 this는 함수가 호출될 때가 아닌 함수가 정의될 때 이미 결정되어 버린다는 것입니다.
var arrow_outer = () => {console.log(this);};
var obj = {
inner: function() { (()=>{console.log(this)})()},
outer: function() {arrow_outer()}
}
obj.inner(); // obj
obj.outer(); // window
위의 예제를 보면 arrow_outer는 이미 외부에서 정의될 때 this는 window를 가리키기 때문에
내부에서 화살표 함수를 사용하면 this=obj를 가리키던 것과는 차이를 보입니다.
arrow function은 일반 함수 호출보다 간결하기 때문에 가독성이 높아집니다. 그래서 특별한 이유가 없다면 사용해도 좋습니다.
일반 함수 표현식보다 구문이 짧고 가독성이 좋음
var nums = [1, 2, 3, 4, 5, 6]
//regular function
var even_fn = nums.filter(function(item) {
return item % 2 == 0
});
//Arrow function
var even_arrow = nuns.filter(item => item % 2 === 0);
console.log(even_fn); // [2,4,6]
console.log(even_arrow); // [2,4,6]
앞의 에제에서 살펴본 것처럼 bind(this) 또는 that=this 등 문법이 필요한 경우, 즉 외부의 this를 주입해야 하는 경우에 간편하게 적용하기 위해 화살표 함수를 사용할 수 있습니다.
화살표 함수를 사용할 수 없는 경우도 있습니다.
var arrow = () => {console.log(this);};
var genFromArrow = new arrow(); // Uncaught TypeError: arrow is not a constructor
ar magicMirror = {
sejelye: '여왕님',
reply: () => {
console.log(`세상에서 제일 예쁜 사람은 ${this.sejelye}입니다.`);
}
}
magicMirror.reply(); // 세상에서 제일 예쁜 사람은 undefined입니다.
<button id="btn1">button_regular</button>
<button id="btn2">button_arrow</button>
<script>
document.getElementById("btn1").addEventListener("click", function(){alert(this.id)}); // btn1
document.getElementById("btn2").addEventListener("click", ()=>{alert(this.id)}); // undefined
</script>