[JS] Arrow Function

기면지·2021년 4월 28일
1

Javascript

목록 보기
2/3
post-thumbnail

안녕하세요, 김현지입니다.
오늘은 자바스크립트 ES6 이후부터 사용된 화살표 함수, Arrow Function에 대해 알아보겠습니다.

Node.js로 백앤드 라우팅 코드를 작성할 때 빈번하게 사용되는 것이 바로 화살표 함수입니다.
처음 화살표 함수를 접했을 때는 코드 흐름에 따라 이해했는데요.
직접 백앤드 코드를 작성하려고하니 정확한 개념 이해가 필요하다는 생각이 들었습니다.

그럼 이제부터 화살표 함수에 대해 알아보겠습니다.


화살표 함수의 선언

화살표 함수는 function 이라는 키워드 대신 => 를 사용합니다.

body

(x) => { return x * x }
(x) => x * x

화살표 함수는 중괄호({})로 묶이지 않은 한줄짜리 바디인 concise 바디와 중괄호({})로 묶인 바디인 block 바디를 사용할 수 있습니다.
concise 바디는 자동으로 값을 반환하기 때문에 return을 생략할 수 있습니다.
하지만, block 바디는 자동으로 값을 반환하지 않기 때문에 return을 사용해서 값을 반환해야 합니다.

parameter

(x) => { logic }
x => { logic }

() => { logic }

매개변수가 하나일 경우에 괄호는 선택사항입니다.
하지만, 매개변수가 없을 경우에는 괄호가 반드시 필요합니다.

객체 리터럴

var func = params => { object: literal }	// func()는 undefined를 반환합니다.
var func = params => ({ object: literal })	// 괄호로 감싸야 합니다.

params => { object: literal }로 표현되는 객체 리터럴 반환은 저 상태로는 동작하지 않습니다.
중괄호({}) 안의 object는 라벨처럼 취급되어 구문이 분석되기 때문인데요, 이것을 해결하기 위해서는 객체 리터럴을 괄호로 감싸야 합니다.

default값, 나머지 매개변수

(x, y, ...arr) => { logic }
(x = 1, y, ..., z = 3) => { logic }

위와 같이 나머지 매개변수를 활용할 수 있고, 매개변수의 default 값도 적용하여 사용할 수 있습니다.

구조분해할당

var ex = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
ex();	// 6

구조분해할당이라는 말이 어렵게 느껴질 수 있을 것 같습니다.
하지만 막상 코드를 살펴보면 default값의 연장선이라고 볼 수도 있을 것 같습니다.
구조를 분해해 할당한다고 풀어서 말할 수 있겠는데요.
위의 코드의 매개변수를 분석해보면 결국, a = 1, b = 2, c = a + b = 3 이 되겠습니다.

화살표 함수의 호출

화살표 함수는 항상 언제나 익명 함수입니다.
따라서 화살표 함수를 호출하기 위해서는 함수 표현식을 사용해야 합니다.

// ES5
var ex = function (x) { return x };
console.log(ex('khyunjiee'));	// khyunjiee

// ES6+
const ex = x => x;
console.log(ex('khyunjiee'));	// khyunjiee

또한 콜백 함수로도 사용이 가능합니다.

// ES5
var arr = [1, 2, 3];
var ex = arr.map(function (x) {
	return x * x;
});
console.log(ex);	// [1, 4, 9]

// ES6+
const arr = [1, 2, 3];
const ex = arr.map(x => x * x);
console.log(ex);	// [1, 4, 9]

화살표 함수에서의 this

일반 함수는 호출 시에 this에 바인딩할 객체가 동적으로 결정됩니다.
하지만, 화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정됩니다.
화살표함수의 this는 일반 함수와는 다르게 언제나 상위 스코프의 this를 가리킵니다.
이를 lexical this라고 부릅니다.

// ES5
var r1 = {
  name: 'zero',
  friends: ['nero', 'hero', 'xero'],
  logFriends: function() {
    var that = this;	// r1을 가리키는 this를 that에 저장
    this.friends.forEach(function(friend) {
      console.log(that.name, friend);
    });
  },
};
r1.logFriends();

위의 코드는 ES5까지 일반 함수에서 사용해온 this입니다.
forEach문 안에서 this 키워드로 r1을 참조할 수 없어 간접적으로 참조하기 위해 that이라는 변수를 사용합니다.

왜 forEach문 안에서는 this 키워드를 사용할 수 없을까요?
그 이유는 일반 함수의 내부함수, 콜백함수에서 사용되는 this는 전역 객체인 window를 사용하기 때문입니다.
위의 코드에서 that이 아닌 this를 사용하면 this.nameundefiend가 됩니다.
window 객체에 name가 없으므로 당연히 undefined가 적용되는 것이죠.

// ES6
const r2 = {
  name: 'zero', 
  friends: ['nero', 'hero', 'xero'],
  logFriends() {
    this.friends.forEach(friend => {
      console.log(this.name, friend);
    });
  },
};
r2.logFriends();

위의 코드는 ES6+부터 화살표 함수를 사용할 때의 this입니다.

왜 화살표 함수에서는 this.name이 정상으로 작동할까요?
화살표 함수에서는 내부함수, 콜백함수에서 사용되는 this가 항상 외부 스코프의 this를 가리키기 때문에 같은 r2를 가리키게 됩니다.
따라서, 정상적으로 ['nero', 'hero', 'xero']에 접근할 수 있는 것입니다.


화살표 함수 사용이 안되는 경우

메소드로 사용

화살표 함수 표현은 메소드 함수가 아닌 형태로만 사용할 수 있습니다.

var obj = {
  i: 10,
  b: () => console.log(this.i, this),
  c: function() {
    console.log(this.i, this)
  }
}

위의 코드에서 화살표 함수를 메소드로 사용한 b가 있습니다.
여기서 obj.b();를 실행하면 어떻게될까요?
obj 객체의 요소들로 this가 바인딩될까요?

아닙니다. 위에서 말씀드렸듯이 화살표 함수의 this는 자신의 상위 스코프가 가리키는 this로 정적 결정됩니다.
따라서 obj가 새로운 스코프, 즉 가장 외부 스코프라면 this는 window를 가리킵니다.
obj.b();의 결과는 undefined, Window {...}가 될 것입니다.

new 연산자 사용 (생성자)

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

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

prototype 속성 사용

화살표 함수는 prototype 속성이 없습니다.
따라서 prototype 속성을 사용하면 undefined로 할당됩니다.

yield 키워드 사용

yield 키워드는 화살표 함수의 본문(중첩된 함수 내부가 아닌)에 사용될 수 없습니다.


참고자료

Node.js 교과서
Arrow function | PoiemaWeb
화살표 함수-JavaScript | MDN

profile
𝙎𝙈𝘼𝙇𝙇 𝙎𝙏𝙀𝙋𝙎 𝙀𝙑𝙀𝙍𝙔 𝘿𝘼𝙔

0개의 댓글