자바스크립트의 객체를 보고 의문이 들었습니다.
대체 prototype이 뭐지? class랑 뭐가 다른거야?
그리고 왜 this의 값은 자바와 다르게 내가 원하는 대로 바인딩 되지 않는거지? 😡

자바스크립트를 사용하여 개발하는 개발자로서 이대로 넘어갈 수 없었습니다 😞
JavaScript의 prototype 을 이해해봅시다.

🧐 프로토타입(prototype)이 뭔데?


자바스크립트의 모든 객체는 다른 객체를 참조하는 특별한 내부 속성인 prototype을 가지고 있습니다. 이 prototype 속성은 또 다른 객체를 참조하거나, 끝에 도달할 때까지 다른 객체들의 체인을 이루며 이를 프로토타입 체인이라고 합니다.

객체의 속성을 참조하려고 할 때, 해당 객체에 그 속성이 없다면, 자바스크립트는 객체의 prototype을 따라가면서 해당 속성을 찾습니다. 이는 프로토타입 체인이 끝날 때까지 계속됩니다. 이렇게 프로토타입 체인을 통해 속성을 찾는 방식을 프로토타입 상속이라고 합니다.

프로토타입과 상속을 활용한 예시 코드를 봅시다 🙂

function Family(name, part) {
    this.name = name;
    this.part = part;
}

Family.prototype.partInfo = function() {
    console.log('내 이름은 ' + this.name + ', 우리집에서 ' + this.part + '을(를) 담당 중!');
}

var jeongInfo = new Family('jeong', '가장');

jeongInfo.partInfo(); // 내 이름은 jeong, 우리집에서 가장을(를) 담당 중!

function Animal(name, part, kind) {
    Family.call(this, name, part);
    this.kind = kind;
}

Animal.prototype = Object.create(Family.prototype);
Animal.prototype.constructor = Animal;

Animal.prototype.kindInfo = function() {
    console.log('나는 ' + this.kind);
}

Animal.prototype.allInfo = function() {
    Family.prototype.partInfo.call(this);
    console.log('참고로 나는 ' + this.kind);
}

var merryInfo = new Animal('메리', '금수', '강아지');
var dalpongInfo = new Animal('달퐁', '금수', '고양이');

merryInfo.partInfo(); // 내 이름은 메리, 우리집에서 금수을(를) 담당 중!
dalpongInfo.allInfo(); // 내 이름은 달퐁, 우리집에서 금수을(를) 담당 중! 참고로 나는 고양이

결과를 보니 this는 실행 컨텍스트에 따라 변하는 것을 확인할 수 있었습니다.
프로토타입 체인을 사용하여 메소드를 상속받아도 this는 호출한 객체를 바라봅니다.
this를 잘 활용하려면 호출 시점을 잘 파악해야 하겠죠?

그리고 es6부터 class 키워드가 도입되어, 클래스 기반 언어처럼 비슷하게 코드를 짤 수 있게 되었습니다! 와~
하지만 여전히 내부에선 프로토타입 기반으로 동작합니다.
아래는 class를 사용한 예시 코드 입니다.

class Family {
    constructor(name, part) {
        this.name = name;
        this.part = part;
    }

    partInfo() {
        console.log('내 이름은 ' + this.name + ', 우리집에서 ' + this.part + '을(를) 담당 중!');
    }
}

let jeongInfo = new Family('jeong', '가장');

jeongInfo.partInfo(); // 내 이름은 jeong, 우리집에서 가장을(를) 담당 중!

class Animal extends Family {
    constructor(name, part, kind) {
        super(name);
        this.part = part;
        this.kind = kind;
    }

    kindInfo() {
        console.log('나는 ' + this.kind);
    }

    allInfo(){
        super.partInfo();
        console.log('참고로 나는 ' + this.kind);
    }
}

let merryInfo = new Animal('메리', '금수', '강아지');
let dalpongInfo = new Animal('달퐁', '금수', '고양이');

merryInfo.partInfo(); // 내 이름은 메리, 우리집에서 금수을(를) 담당 중!
dalpongInfo.allInfo(); // 내 이름은 달퐁, 우리집에서 금수을(를) 담당 중! 참고로 나는 고양이

ㅋㅋ
class를 사용하니 확실히 this를 파악하기 편해진 것 같습니다..^^

🧐 프로토타입으로 할 수 있는 것


class와 prototype은 상속을 통해 속성 및 메서드를 자식이 재사용할 수 있다는 공통점을 가지고 있지만 명확한 차이가 있어요.
예를들어 자바의 클래스는 컴파일 시점에 정의되어 더이상 수정할 수 없는 정적 객체이지만, 자바스크립트의 프로토타입은 동적이기 때문에 코드가 실행되는 와중에도 객체의 동작을 동적으로 변경할 수 있습니다.
왜 이렇게 다르게 만들어졌는가? 라는 의문이 든다면 해당 언어가 추구하는 철학을 이해해야하죠…
자바로 프로그램을 짤 때엔 엄격한 구조와 규칙을 지켰어야 했지만
(규칙을 지키지 않으면 컴파일부터 되지 않는–;;;)
자바스크립트는 그런 것이 없죠… 자유로운게.. 참 알면 알수록 머리아프고 매력적인 언어입니다..~