본문으로 바로가기
반응형

화살표 함수 (Arrow Function)는 ES6에 추가된 것으로, 기존의 일반 함수 표현보다 짧은 구문으로 가독성 높은 코드를 작성할 수 있게 도와줍니다. 아마도 요즘 자바스크립트를 공부하는 분들은 거의 대부분 화살표 모양의 함수를 보거나 사용한 적이 있을 것으로 생각됩니다.

 

2019에 가장 많이 사용된 자바스크립트 기능!

출처: state of javascript (https://2019.stateofjs.com/awards/)

 

 

이번 글에서는 무심코 사용해왔던 화살표 함수에 대해서 다음과 같은 내용으로 살펴보겠습니다.

  • 화살표 함수의 기본 문법
  • 화살표 함수의 this
  • 언제 사용해야 할까?
  • 언제 사용하지 말아야 할까?

 

 

1. 화살표 함수의 기본 문법

먼저 화살표 함수(Arrow function)에 대해서 자세히 파헤치기 전에 기본 문법에 대해서 살펴보겠습니다.

1.1 기본형

[일반 함수 선언]

기존의 일반 함수(regular function) 선언은 다음과 같이 'function'을 이용하여 구성합니다.

var sum = function(a, b) { 
  return a + b; 
}

 

[ES6 화살표 함수]

ES6에 추가된 화살표 함수 표기법을 이용하면 아래와 같은 코드로 위와 동일한 기능을 표현할 수 있습니다.

var sum = (a, b) => { 
  return a + b; 
};

 

처음에는 약간 어색한데, 사용하다 보면 코드의 가독성이 높아지더군요. 특히 callback 함수로 사용할 때 특히 그 효과가 큰 것 같습니다.

 

1.2 argument가 1개만 있는 경우 ( ) 생략 가능

만약 argument에 1개의 파라미터만 있는 경우에는 파라미터의 괄호를 생략할 수 있습니다.

var greeting = (hello) => { 
  return hello + ' world'; 
};

// 축약형
var greeting = hello => { 
  return hello + ' world'; 
};

 

1.3 내용에 return 값만 있는 경우 { }와 return 생략 가능

화살표 함수에는 반환 구문을 단축하는 방법도 내장되어 있습니다. 화살표 함수가 반환(return) 코드로만 구현되어 있는 경우, 괄호와 return 키워드를 생략할 수 있습니다. 

var sum = (a, b) => { return a + b; };

// 축약형
var sum = (a, b) => a + b;

 

2. 화살표 함수의 this

This에 관한 글에서 함수를 선언할 때 this에 바인딩할 객체가 결정되는 것이 아니고, 함수를 어떻게 호출하느냐에 따라서 this가 가리키는 객체가 결정되는 것을 확인하였습니다. 일반 함수에서의 this와 관련한 아래 글을 먼저 참조하시기 바랍니다.

 

[JavaScript] 예제로 이해하는 this

자바스크립트(JavaScript)코드를 보면, 가끔씩 보이는 변수 선언들이 있습니다. var self = this; var that = this; var _this = this; ... 남들이 쓰니까 쓰기는 하는데... 뭔가 약간 알듯말듯 애매합니다. 좀 더..

paperblock.tistory.com

 

 

화살표 함수의 경우는 이와 다릅니다.

 

화살표 함수를 사용하는 경우에는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다.  화살표 함수는 this에 대한 binding이 없으며 화살표 함수가 정의되어있는 객체의 스코프를 그대로 가지고 있다. 따라서 화살표 함수 내의 this는 상위 스코프의 this를 의미한다.

 

뭐...

그렇다고 합니다....

잘 모를 때는 예제로......

 

다시 한번 '백설공주'와 'this'를 소환해 봅니다.

 

 

Magic Mirror의 위기

 

마법의 거울은 살아남기 위해서는 제일 예쁜 사람은 여왕님이라고 말해야 합니다.

글로벌하게는 '백설공주'이지만

이미 내부적으로 sejelye는 여왕님이라고 계속 되뇌었습니다.

그런데, 무슨 이유에선지... 대답을 할 때는 자꾸

"제일 예쁜 사람은 백설공주"

라고 이야기합니다. 

 

 

마법의 거울이 살아남기 위해서는 magicMirror 객체 안의 프로퍼티 sejelye를 참조해서 대답을 해야 합니다. 그런데 거울이 대답하는 부분 (console.log)은 객체안의 메서드로 실행되는 것이 아니라 setTimeout을 이용하여 내부 함수로 실행되고 있네요.

 

This 관련 글에서 살펴본 바와 같이 내부 함수의 경우, this는 기본적으로 전역 객체(window)를 가리킵니다. 따라서 ①의 경우에는 sejelye는 백설공주를 나타내게 됩니다.

어떻게 하면 내부 함수로 호출되면서도 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를 가리키던 것과는 차이를 보입니다.

 

3. 화살표 함수는 언제 사용해야 할까요?

언제 Arrow function을 써야 할까요?

처음에는 어색했는데 자꾸 쓰다 보면 function()... 보다 훨씬 간결하고 코드의 가독성이 높아집니다. 그래서 특별한 이유가 없다면 사용해 주는 것이 좋습니다.

✅ this가 필요 없는 일반 함수

일반 함수 표현식보다 구문이 짧고 가독성이 좋습니다.

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 = nums.filter(item => item % 2 === 0);

console.log(even_fn) // [2,4,6]
console.log(even_arrow) // [2,4,6]

 

위의 예에서 화살표 기능을 사용하면 이러한 이점을 모두 볼 수 있습니다. ES5 Array Method를 사용할 때 filter의 콜백 함수로 일반 함수와 화살표 함수를 비교하였습니다. 첫 번째는 간단한 함수 표현식을 사용하고 두 번째는 화살표 함수를 사용합니다. 둘을 비교해보면, 화살표 함수를 사용한 두 번째 표현식의 구문이 더 짧고 가독성이 좋아 보입니다.

 

사실상 this를 사용하지 않는 경우라면 기존의 function과 동일하게 생각하고 사용하면 됩니다.

✅ 내부 함수 등에서 bind(this)의 대체

앞의 예제에서 살펴본 것처럼 bind(this) 또는 that=this 등의 문법이 필요한 경우, 즉 외부의 this를 주입해야 하는 경우에 간편하게 적용하기 위해 화살표 함수를 사용할 수 있습니다.

 

4. 화살표 함수를 사용하면 안 되는 경우는?

뭔가 좋아 보이는 화살표 함수!

하지만 화살표 함수를 사용할 수 없는 경우가 있습니다.

 

❎ 생성자 함수로는 사용할 수 없다.

var arrow = () => {console.log(this);};
var genFromArrow = new arrow(); // Uncaught TypeError: arrow is not a constructor

 

❎ 객체 또는 프로토타입 메서드에서 객체를 참조해야 하는 경우

var magicMirror = {
  sejelye: '여왕님', 
  reply: () => {
     console.log(`세상에서 제일 예쁜 사람은 ${this.sejelye}입니다.`); 
  }
}

magicMirror.reply(); // 세상에서 제일 예쁜 사람은 undefined입니다.

 

❎ DOM EventHandler에서 Element에 접근해야 하는 경우

<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>

 

앞에서 살펴본 바에 따라 this의 의미를 따라가 보면 비교적 쉽게 이해될 것으로 생각됩니다.

 

맺음말

이번 글에서는 요즘에는 자주 사용되는 ES6의 화살표 함수에 대해서 알아보았습니다. 가독성이나 편의성으로 볼 때, 특별한 예외 상황에 해당하는 경우가 아니라면, 화살표 함수를 사용하는 습관을 들이는 게 좋을 것 같습니다. 다만, this에 대해서만 약간 주의하면 될 것 같네요. ^^

 

반응형