개발하는 상황에서 주로 화살표 함수를 많이 사용했지만, 여러 코드를 보면서 일반 함수를 사용하는 경우도 종종 보았다. 화살표 함수, 일반 함수를 선택하는 근거가 있어야 한다고 판단하여 나의 기준을 세워보려한다.
1. 메서드를 정의할 때
메서드를 정의할 때 화살표 함수를 사용하면, this가 전역객체(window)를 가르키기 때문에 원치않는 결과를 얻게된다. 대체로 전역객체 를 this로 가리킬 상황은 드문 것 같다.
// Bad
const person = {
name: 'Lee',
sayHi: () => console.log(`Hi ${this.name}`)
};
// sayHi 프로퍼티에 할당된 화살표 함수 내부의 this는 상위 스코프인 전역의 this가 가리키는
// 전역 객체를 가리키므로 이 예제를 브라우저에서 실행하면 this.name은 빈 문자열을 갖는
// window.name과 같다. 전역 객체 window에는 빌트인 프로퍼티 name이 존재한다.
person.sayHi(); // Hi
// Good
const person = {
name: 'Lee',
sayHi() {
console.log(`Hi ${this.name}`);
}
};
person.sayHi(); // Hi Lee
단 this를 사용하지 않는 경우에는 화살표 함수를 사용해도 상관없다.
생성자 함수와 클래스에 대해서도 각각 시험을 해봤는데 내 생각과는 달리 동작해서 이것도 기록한다.
클래스에서 sayHi 필드에 화살표 함수를 할당할 경우 이 내부의 this 는 상위 스코프인 window를 가르킬 것으로 예상했다. 하지만 이 경우는 클래스 외부의 this 를 참조하지 않고 클래스가 생성할 인스턴스를 가르킨다고 한다.
화살표함수가 this 가르키는 예외적인 상황으로 기억해두자.
class Person {
// 생성자
constructor(name) {
// 인스턴스 생성 및 초기화
this.name = name;
}
// 프로토타입 메서드
sayHi() {
console.log(`Hi! My name is ${this.name}`); // Hi! My name is uzi
}
}
class ArrowPerson {
// 생성자
constructor(name) {
// 인스턴스 생성 및 초기화
this.name = name;
}
sayHi = () => {
console.log(`Hi! My name is ${this.name}`); // Hi! My name is uzi
}
}
class ConstructorArrowPerson {
// 생성자
constructor(name) {
// 인스턴스 생성 및 초기화
this.name = name;
this.sayHi = () => {
console.log(`Hi! My name is ${this.name}`); // Hi! My name is uzi
}
}
}
const person = new Person('uzi')
person.sayHi()
const arrowPerson = new ArrowPerson('uzi')
arrowPerson.sayHi()
const constructorArrowPerson = new ConstructorArrowPerson('uzi')
arrowPerson.sayHi()
그럼 클래스에서는 메소드 정의할 때 화살표 함수 써도 되는가? 라고 생각할 수 있다. 하지만 이 경우도 지양하는 것이 좋다.
이유는 화살표 함수로 정의한다면 프로토타입 메서드가 아닌 인스턴스 메서드가 생성된다. 이는 불필요한 메모리를 낭비하게 한다. 아마 프로덕트에 큰 영향을 끼치지는 않겠지만, 아는 것과 모르는 것은 차이가 크다.
생성자 함수도 클래스 외부의 this 를 참조하지 않고 클래스가 생성할 인스턴스를 가르킨다고 한다. 이때 두가지 경우 모두 인스턴스 메서드로 생성된다.
function Circle(radius) {
this.radius = radius;
this.getArea = function () {
// Math.PI는 원주율을 나타내는 상수다.
return Math.PI * this.radius ** 2;
};
}
function ArrowCircle(radius) {
this.radius = radius;
this.getArea = () => {
// Math.PI는 원주율을 나타내는 상수다.
return Math.PI * this.radius ** 2;
};
}
const circle = new Circle(5);
console.log(circle)
console.log(circle.getArea())
const arrowCircle = new ArrowCircle(5);
console.log(arrowCircle)
console.log(arrowCircle.getArea())
2. 프로토타입 메서드를 정의할 때
프로토타입 메서드를 정의할 때 화살표 함수를 사용하면 이 경우에 this 가 전역객체를 가르켜 원치 않은 결과를 얻는다.
// Bad
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = () => console.log(`Hi ${this.name}`);
const person = new Person('Lee');
// 이 예제를 브라우저에서 실행하면 this.name은 빈 문자열을 갖는 window.name과 같다.
person.sayHi(); // Hi
// Good
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = function () { console.log(`Hi ${this.name}`); };
const person = new Person('Lee');
person.sayHi(); // Hi Lee
이 두가지 경우 외에는 괜찮다고 생각하는데, 또 발견한다면 업데이트 해야겠다.
'FrontEnd > JS' 카테고리의 다른 글
클래스 (4) | 2023.06.03 |
---|---|
프로토타입 (0) | 2023.06.02 |
async / await (2) | 2023.05.31 |
this (0) | 2023.05.30 |
프로미스 (5) | 2023.05.30 |