함정 시리즈

[JavaScript] 객체의 프로토타입에 메서드 추가하기

노새두마리 2023. 12. 23. 23:38

 

화살표 함수 대신 function 키워드 쓰세요

Set.prototype.toggle

Set에 함수의 인자로써 주어진 데이터가 없다면 데이터를 추가하고, 데이터가 이미 있다면 데이터를 삭제하는 toggle 메서드를 추가해 봅시다.

방법

다음의 과정을 거치면 Set.prototype.add, Set.prototype.remove와 같은 Set 자료형의 다른 메서드처럼 우리가 만든 toggle 함수를 호출할 수 있습니다.

1. 함수를 정의한다.

2. Set.prototype의 하위에 1에서 정의된 함수를 할당한다.


함수 정의 및 할당

// 함정
Set.prototype.toggle = (item) => {
    if (this.has(item)){
        this.delete(item);
    } else {
        this.add(item);
    }
}

this를 사용하여 다른 메서드들과 동일한 형태로 데이터만을 인자로 하여 함수를 호출하고, 우리가 변경하고자 하는 객체에 대해서는 this를 통해 참조할 수 있도록 함수를 정의합니다.

toggle 메서드를 호출할 때마다 setA.toggle(setA, item)처럼 호출해야 한다면 사용하기에도 보기에도 굉장히 불편할 것입니다. 이런 형태는 객체 레벨에서 호출하는 메서드 보다는 클래스 정적 메서드가 가지는 모양새에 가깝습니다.


함정

이제 새로운 Set 자료형을 선언해서 메서드를 호출해 봅시다!

const setA = new Set();
setA.toggle(1224);

!!!

화살표 함수를 사용하였다면 this가 의도한 대로 바인딩되지 않아서 has, add, delete 등 다른 메서드를 호출할 수 없습니다.


해결

화살표 함수 대신 function 키워드를 사용하면 함수 안에서 this를 통해 다른 메서드를 호출할 수 있습니다.

Set.prototype.toggle = function (item){
    if (this.has(item)){
        this.delete(item);
    } else {
        this.add(item);
    }
}

const setA = new Set();
setA.toggle(1224);
setA; // { 1224 }
setA.toggle(1224);
setA; // { }

원인

화살표 함수의 this가 function 키워드로 선언된 함수의 this가 다르기 때문에 발생하는 현상입니다.

function 키워드로 선언된 함수는 함수가 실행되는 맥락을 고려하여 달라질 수 있는 반면에 화살표 함수는 함수가 정의되는 시점과 클로저에 의해 결정됩니다.

크게 두 가지로 볼 수 있을 것 같습니다.

  1. 클래스 내부에서 정의된 화살표 함수의 this는 객체(인스턴스 또는 클래스 자체)
  2. 클래스 외부에서 정의된 화살표 함수의 this는 전역 객체
class Duck {
    constructor(){
        this.sound = 'quack!';
    }
    quack = () => console.log(this.sound);
}
Duck.prototype.quack2 = () => console.log(this.sound);

const duck = new Duck();

// 1. 클래스 내부에서 정의된 화살표 함수
duck.quack(); // quack!

// 2. 클래스 외부에서 정의된 화살표 함수
duck.quack2(); // undefined

참고

this

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this

화살표 함수

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/Arrow_functions#%EB%A9%94%EC%84%9C%EB%93%9C%EB%A1%9C_%EC%82%AC%EC%9A%A9%ED%95%A0_%EC%88%98_%EC%97%86%EC%8A%B5%EB%8B%88%EB%8B%A4