본문 바로가기
JS

화살표 함수(Arrow Function)

by Hyeon_E 2024. 6. 11.

화살표 함수(Arrow Function)

ES6부터 화살표 함수라는 새로운 문법 방식으로 함수를 만들 수 있게 됨

화살표 함수는 function 키워드 대신 화살표(=>)를 사용하여 보다 간략한 방법으로 함수를 선언할 수 있지만

모든 경우 화살표 함수를 사용할 수 있는 것은 아님

 

▶ 화살표 함수 문법 표현

매개변수 표현

매개변수가 하나뿐이면 매개변수의 괄호 부분을 생략

// 매개변수가 없을 경우
() => { ... } 

// 매개변수가 한 개인 경우, 소괄호를 생략할 수 있음
x => { ... } 

// 매개변수가 여러 개인 경우, 소괄호를 생략할 수 없음
(x, y) => { ... }

 

함수 몸체 표현

함수 몸체 내의 코드가 한줄이고 단순히 return문 밖에 없다면 중괄호와 return 키워드생략

// single line block
x => { return x * x }  

// 함수 몸체가 한줄의 구문이라면 중괄호를 생략할 수 있으며 암묵적으로 return
x => x * x

 

객체 리터럴 반환

객체 리터럴을 반환하려면 소괄호('()')로 감싸야 함

왜냐하면 딸랑 중괄호 { } 쓰면 얘가 함수 블록인지 객체 블록인지 판단할수 없기 때문

 

() => { return { a: 1 }; }

() => ({ a: 1 })  // 위 표현과 동일하다. 객체 반환시 소괄호를 사용한다.

 

고급 조합 표현

// 매개변수 기본값
(a = 1, b = 2) => a + b; 

// 나머지 매개변수
(...args) => args; 

// 구조 분해 할당
([a, b] = [1, 2]) => a + b;

 

let age = prompt("나이를 알려주세요.", 18);

let welcome = (age < 18) ?
  () => alert('안녕') :
  () => alert("안녕하세요!");

welcome();

 

 

▶ 화살표 함수의 호출

화살표 함수는 익명 함수로만 사용할 수 있음

따라서 화살표 함수를 호출하기 위해서는 함수 표현식을 사용

 

// ES5
var pow = function (x) { return x * x; };
console.log(pow(10)); // 100

// ES6
const pow = x => x * x;
console.log(pow(10)); // 100

 

또는 콜백 함수로 사용할 수 있음 이 경우 일반적인 함수 표현식보다 표현이 간결

 

// ES5
var arr = [1, 2, 3];
var pow = arr.map(function (x) { // x는 요소값
  return x * x;
});

console.log(pow); // [ 1, 4, 9 ]

// ES6
const arr = [1, 2, 3];
const pow = arr.map(x => x * x);

console.log(pow); // [ 1, 4, 9 ]

 

▶ 일반함수와 화살표 함수의 차이

인스턴스

const Person = (name) => {
    this.name = name;
};

const john = new Person("John"); // 에러 발생: Person is not a constructor

 

화살표 함수는 일반 함수와 달리 인스턴스를 생성할 수없음(non-constructor)

그렇기 때문에 prototype 속성이 없고, 프로토타입도 생성하지 않음습니다.

 

const Person = (name) => {
    this.name = name;
};

console.log(Person.hasOwnProperty("prototype")); // false

 

this

일반 함수의 this

자바스크립트의 경우 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정

다시 말해, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고

함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정


콜백 함수 내부this전역 객체 window를 가리킴

 

function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function (arr) {
  // (A)
  return arr.map(function (x) {
    return this.prefix + ' ' + x; // (B)
  });
};

var pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));  // ['undefined Lee', 'undefined Kim']

 

(A) 지점에서의 this는 생성자 함수 Prefixer가 생성한 객체, 즉 생성자 함수의 인스턴스(위으 예제의 경우 pre)
(B) 지점에서 사용한 this는 전역 객체 window

 

이렇게 된 이유는 생성자 함수와 객체의 메소드를 제외한 모든 함수(내부 함수, 콜백 함수 포함) 내부의 this는 전역 객체를 가리키기 때문

콜백 함수 내부의 this가 메소드를 호출한 객체(생성자 함수의 인스턴스)를 가리키게 하려면 여러가지 방법이 있음

 

// Solution 1: that = this
function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function (arr) {
  var that = this;  // this: Prefixer 생성자 함수의 인스턴스
  return arr.map(function (x) {
    return that.prefix + ' ' + x;
  });
};

var pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));

 

// Solution 2: map(func, this)
function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function (arr) {
  return arr.map(function (x) {
    return this.prefix + ' ' + x;
  }, this); // this: Prefixer 생성자 함수의 인스턴스
};

var pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));

 

// Solution 3: bind(this)
function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function (arr) {
  return arr.map(function (x) {
    return this.prefix + ' ' + x;
  }.bind(this)); // this: Prefixer 생성자 함수의 인스턴스
};

var pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));

 

화살표 함수의 this

화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정

동적으로 결정되는 일반 함수와는 달리 화살표 함수의 this 언제나 상위 스코프의 this를 가리킴(이를 Lexical this라 함)

 

function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function (arr) {
  // this는 상위 스코프인 prefixArray 메소드 내의 this를 가리킨다.
  return arr.map(x => `${this.prefix}  ${x}`);
};

const pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));

 

화살표 함수는 call, apply, bind 메소드를 사용하여 this를 변경할 수 없음

 

window.x = 1;
const normal = function () { return this.x; };
const arrow = () => this.x;

console.log(normal.call({ x: 10 })); // 10
console.log(arrow.call({ x: 10 }));  // 1

 

arguments 

arguments 객체함수 내에서 인수에 접근하는 데 사용되는데, 일반 함수에서는 이 객체를 사용할 수 있지만 화살표 함수에서는 사용할 수 없음

function sumWithArguments() {
    let sum = 0;
    
    for (let i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    
    return sum;
}

const sumWithArrow = () => {
    let sum = 0;
    
    for (let i = 0; i < arguments.length; i++) {
        sum += arguments[i]; // 여기서 arguments를 사용하면 에러가 발생
    }
    
    return sum;
}

console.log(sumWithArguments(1, 2, 3, 4, 5)); // 출력: 15
console.log(sumWithArrow(1, 2, 3, 4, 5)); // 에러 발생: arguments is not defined

 

sumWithArrow 함수는 화살표 함수로 선언되어서 arguments를 사용하려고 할 때 에러가 발생

 

화살표 함수는 자신만 arguments 객체를 가지지 않기 때문

따라서, 인수에 접근해야 하는 경우에는 일반 함수를 사용하는 것이 좋음

▶ 화살표 함수를 사용해서는 안되는 경우

화살표 함수는 Lexical this를 지원하므로 콜백 함수로 사용하기 편리

하지만 화살표 함수를 사용하는 것이 오히려 혼란을 불러오는 경우도 있으므로 주의해야 함

 

메소드

화살표 함수로 메소드를 정의하는 것은 피해야 함

 

// Bad
const person = {
  name: 'Lee',
  sayHi: () => console.log(`Hi ${this.name}`)
};

person.sayHi(); // Hi undefined

 

메소드로 정의한 화살표 함수 내부의 this는 메소드를 소유한 객체, 즉 메소드를 호출한 객체를 가리키지 않고 상위 컨택스트인 전역 객체 window를 가리킴 따라서 화살표 함수로 메소드를 정의하는 것은 바람직하지 않음

이와 같은 경우는 메소드를 위한 단축 표기법인 ES6의 축약 메소드 표현을 사용하는 것이 좋음

 

// Good
const person = {
  name: 'Lee',
  sayHi() { // === sayHi: function() {
    console.log(`Hi ${this.name}`);
  }
};

person.sayHi(); // Hi Lee

 

prototype

화살표 함수로 정의된 메소드를 prototype에 할당하는 경우도 동일한 문제가 발생

 

// Bad
const person = {
  name: 'Lee',
};

Object.prototype.sayHi = () => console.log(`Hi ${this.name}`);

person.sayHi(); // Hi undefined

 

prototype에 메소드를 할당하는 경우, 일반 함수를 할당

 

// Good
const person = {
  name: 'Lee',
};

Object.prototype.sayHi = function() {
  console.log(`Hi ${this.name}`);
};

person.sayHi(); // Hi Lee

 

생성자 함수

화살표 함수는 생성자 함수로 사용할 수 없음

생성자 함수는 prototype 프로퍼티를 가지며 prototype 프로퍼티가 가리키는 프로토타입 객체의 constructor를 사용

하지만 화살표 함수는 prototype 프로퍼티를 가지고 있지 않음

 

const Foo = () => {};

// 화살표 함수는 prototype 프로퍼티가 없다
console.log(Foo.hasOwnProperty('prototype')); // false

const foo = new Foo(); // TypeError: Foo is not a constructor

 

addEventListener 함수의 콜백 함수

addEventListener 함수의 콜백 함수를 화살표 함수로 정의하면 this가 상위 컨택스트인 전역 객체 window를 가리킴

 

// Bad
var button = document.getElementById('myButton');

button.addEventListener('click', () => {
  console.log(this === window); // => true
  this.innerHTML = 'Clicked button';
});

 

addEventListener 함수의 콜백 함수 내에서 this를 사용하는 경우, function 키워드로 정의한 일반 함수를 사용

일반 함수로 정의된 addEventListener 함수의 콜백 함수 내부의 this는 이벤트 리스너에 바인딩된 요소(currentTarget)를 가리킴

 

// Good
var button = document.getElementById('myButton');

button.addEventListener('click', function() {
  console.log(this === button); // => true
  this.innerHTML = 'Clicked button';
});

 

 

Reference 

자바스크립트 화살표 함수 사용법 총정리

6.3 Arrow function 화살표 함수

자바스크립트 화살표 함수의 이해와 사용법

댓글