[JS ν”„λ‘œν† νƒ€μž…] ν”„λ‘œν† νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ μƒμ†ν•˜κΈ°

    [JS ν”„λ‘œν† νƒ€μž…] ν”„λ‘œν† νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ μƒμ†ν•˜κΈ°


    이번 ν¬μŠ€νŒ…μ—μ„œλŠ” 이전 ν¬μŠ€νŒ…μ— 이어, ν”„λ‘œν† νƒ€μž…μ„ μ‚¬μš©ν•œ λ‹€μ–‘ν•œ 상속 νŒ¨ν„΄μ— λŒ€ν•œ 이야기λ₯Ό ν•΄λ³ΌκΉŒ ν•œλ‹€.

    사싀 μžλ°”μŠ€ν¬λ¦½νŠΈμ—λŠ” μƒμ†μ΄λ‚˜ μΊ‘μŠν™”μ™€ 같은 κ°œλ…μ΄ λͺ…μ‹œμ μœΌλ‘œ μ‘΄μž¬ν•˜μ§€λŠ” μ•ŠκΈ° λ•Œλ¬Έμ— μžλ°”λ‚˜ C++ 같은 클래슀 기반 μ–Έμ–΄λ₯Ό μ‚¬μš©ν•˜λ˜ κ°œλ°œμžλ“€μ€ μžλ°”μŠ€ν¬λ¦½νŠΈμ— ν΄λž˜μŠ€κ°€ μ—†λ‹€λŠ” 사싀에 ν˜Όλž€μŠ€λŸ¬μ›Œν•œλ‹€.

    즉, μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œμ˜ μƒμ†μ΄λ‚˜ μΊ‘μŠν™” 등은 OOP(객체지ν–₯ν”„λ‘œκ·Έλž˜λ°)에 μ΅μˆ™ν•œ κ°œλ°œμžλ“€μ΄ μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œλ„ 이런 κ°œλ…λ“€μ„ κ°€μ Έλ‹€ μ‚¬μš©ν•˜κΈ° μœ„ν•΄ ν”„ν† ν† νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ 이λ₯Ό μœ μ‚¬ν•˜κ²Œ κ΅¬ν˜„ν•œ μΌμ’…μ˜ λ””μžμΈ νŒ¨ν„΄μ΄λΌκ³  ν•  수 μžˆλ‹€.

    μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œμ˜ 상속은 ν”„λ‘œν† νƒ€μž… 체인을 μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•˜κ³ , μΊ‘μŠν™”λŠ” ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•΄μ„œ κ΅¬ν˜„ν•˜κ²Œ λ˜λŠ”λ°, 이번 ν¬μŠ€νŒ…μ—μ„œλŠ” 이 쀑 ν”„λ‘œν† νƒ€μž…μ„ μ‚¬μš©ν•œ 상속 νŒ¨ν„΄μ— μ§‘μ€‘ν•΄μ„œ μ„€λͺ…ν•΄λ³ΌκΉŒ ν•œλ‹€.

    ν”„λ‘œνΌν‹°μ™€ λ©”μ†Œλ“œλŠ” 원본 객체λ₯Ό 톡해 곡유될 수 μžˆλ‹€

    객체의 상속을 μ•Œμ•„λ³΄κΈ° 전에 객체λ₯Ό 생성할 λ•Œ ν”„λ‘œνΌν‹°μ™€ λ©”μ†Œλ“œλ₯Ό λΆ€μ—¬ν•˜λŠ” 방법에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄λ„λ‘ ν•˜μž. 이전 ν¬μŠ€νŒ…μ—μ„œ ν•„μžλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” ν΄λž˜μŠ€κ°€ μ•„λ‹Œ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 객체λ₯Ό μƒμ„±ν•œλ‹€κ³  이야기 ν–ˆμ—ˆλ‹€.

    function User () {}
    const evan = new User();

    μ΄λ•Œ User ν•¨μˆ˜λ₯Ό μƒμ„±μžλ‘œ ν˜ΈμΆœν•˜λ©΄μ„œ μƒμ„±λœ evan κ°μ²΄λŠ” User.prototype 객체λ₯Ό 원본 객체둜 ν•˜μ—¬ 볡제된 객체이닀.

    μ΄λ•Œ 두 κ°€μ§€ 방법을 μ‚¬μš©ν•˜μ—¬ μƒˆλ‘­κ²Œ μƒμ„±λ˜λŠ” κ°μ²΄λ“€μ—κ²Œ ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλ₯Ό λΆ€μ—¬ν•  수 μžˆλŠ”λ°, 첫 λ²ˆμ§ΈλŠ” μƒμ„±μž ν•¨μˆ˜ λ‚΄μ—μ„œ thisλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„ μ–Έν•˜λŠ” 방법, 두 λ²ˆμ§ΈλŠ” μƒˆλ‘­κ²Œ μƒμ„±λ˜λŠ” 객체듀이 볡사할 원본 객체인 ν”„λ‘œν† νƒ€μž… 객체에 μ„ μ–Έν•˜λŠ” 방법이닀.

    λ¨Όμ €, thisλ₯Ό μ‚¬μš©ν•˜μ—¬ ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλ₯Ό μ •μ˜ν•˜λŠ” 방법에 λŒ€ν•΄μ„œ μ‚΄νŽ΄λ³΄μž.

    μƒμ„±μž ν•¨μˆ˜ λ‚΄μ—μ„œ thisλ₯Ό μ‚¬μš©ν•˜λŠ” 방법

    μžλ°”μŠ€ν¬λ¦½νŠΈλ„ μƒμ„±μž 역할을 ν•˜λŠ” ν•¨μˆ˜ λ‚΄μ—μ„œ thisλ₯Ό μ‚¬μš©ν•˜μ—¬ λ‹€λ₯Έ 언어와 λΉ„μŠ·ν•œ λŠλ‚ŒμœΌλ‘œ κ°μ²΄λ“€μ—κ²Œ ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλ₯Ό λΆ€μ—¬ν•  수 μžˆλ‹€.

    function User (name) {
      'use strict';
      this.say = function () {
        console.log('Hello, World!');
      };
    }
    
    const evan = new User();
    console.log(evan.say());
    Hello, World!

    참고둜 μƒμ„±μž ν•¨μˆ˜ λ‚΄μ—μ„œ strict λͺ¨λ“œλ₯Ό μ‚¬μš©ν•œ μ΄μœ λŠ”, ν•΄λ‹Ή μƒμ„±μž ν•¨μˆ˜κ°€ μ‹€μˆ˜λ‘œ new μ˜ˆμ•½μ–΄ 없이 ν˜ΈμΆœλ˜μ–΄ thisκ°€ μ „μ—­ 객체둜 ν‰κ°€λ˜λŠ” λΆˆμƒμ‚¬λ₯Ό λ°©μ–΄ν•˜κΈ° μœ„ν•΄μ„œμ΄λ‹€.(이 λ‚΄μš©μ€ ν”„λ‘œν† νƒ€μž…κ³ΌλŠ” 관련이 μ—†κΈ° λ•Œλ¬Έμ— μžμ„Ένžˆ λ‹€λ£¨μ§€λŠ” μ•Šκ² λ‹€)

    이 방법은 일반적인 μƒμ„±μžμ˜ μ‚¬μš© 방법과 λΉ„μŠ·ν•΄μ„œ μ§κ΄€μ μœΌλ‘œ 이해가 λ˜λŠ” νŽΈμ΄λ‹€. μ΄λ•Œ μƒμ„±μž ν•¨μˆ˜ μ•ˆμ˜ thisλŠ” μƒˆλ‘­κ²Œ μƒμ„±λœ 객체λ₯Ό μ˜λ―Έν•˜κΈ° λ•Œλ¬Έμ—, ν•¨μˆ˜ λ‚΄μ—μ„œ thisλ₯Ό 톡해 μ •μ˜ν•œ ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλŠ” 이 μƒμ„±μž ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 객체가 생성될 λ•Œλ§ˆλ‹€ μƒˆλ‘­κ²Œ μ •μ˜λœλ‹€.

    무슨 말인지 쑰금 더 μ‰½κ²Œ μ•Œμ•„λ³΄κΈ° μœ„ν•΄ μƒμ„±μž ν•¨μˆ˜λ₯Ό 톡해 두 개의 μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•˜κ³ , 이 κ°μ²΄λ“€μ˜ λ©”μ†Œλ“œλ₯Ό 비ꡐ해도둝 ν•˜μž.

    const evan = new User();
    const john = new User();
    
    console.log(evan.say === john.say);
    false

    μƒμ„±μž ν•¨μˆ˜κ°€ 호좜될 λ•Œ thisλŠ” 각각 evan 객체와 john 객체λ₯Ό μ˜λ―Έν–ˆμ„ 것이고, say λ©”μ†Œλ“œ λ˜ν•œ 이 κ°μ²΄λ“€μ—κ²Œ 직접 ν• λ‹Ήλ˜μ—ˆμ„ 것이닀. μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μ™„μ „ν• λ‹Ήμ—°μ‚°μž(===)λŠ” λ‹€λ₯Έ λ©”λͺ¨λ¦¬μ— 적재된 κ°μ²΄λŠ” λ‹€λ₯΄λ‹€κ³  ν‰κ°€ν•˜λ―€λ‘œ 이 두 객체의 λ©”μ†Œλ“œλ“€μ€ 각자 λ‹€λ₯Έ λ©”λͺ¨λ¦¬μ— λ‹΄κΈ΄, μ „ν˜€ λ‹€λ₯Έ ν•¨μˆ˜λΌκ³  ν•  수 μžˆλ‹€.

    μ΄λ•Œ evan κ°μ²΄λ‚˜ john 객체λ₯Ό 좜λ ₯해보면, 객체 내뢀에 say λ©”μ†Œλ“œκ°€ μ •μ˜λ˜μ–΄ μžˆλŠ” λͺ¨μŠ΅ λ˜ν•œ 확인해볼 수 μžˆλ‹€.

    console.log(evan);
    User {say: function}

    이 λ‹Ήμ—°ν•œ 이야기λ₯Ό ν•˜λŠ” μ΄μœ λŠ” λ°”λ‘œ λ°‘μ—μ„œ ν›„μˆ ν•  ν”„λ‘œν† νƒ€μž… 객체에 μ •μ˜ν•˜λŠ” 방법과 차이점을 λΆ„λͺ…νžˆ ν•˜κΈ° μœ„ν•΄μ„œμ΄λ‹€. ν”„λ‘œν† νƒ€μž… 객체λ₯Ό μ‚¬μš©ν•΄μ„œ ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλ₯Ό μ •μ˜ν•˜κ²Œλ˜λ©΄ μ§€κΈˆκ³ΌλŠ” μ „ν˜€ λ‹€λ₯Έ κ²°κ³Όκ°€ λ‚˜μ˜¨λ‹€.

    ν”„λ‘œν† νƒ€μž… 객체에 μ •μ˜ν•˜λŠ” 방법

    μ΄λ²ˆμ—λŠ” User μƒμ„±μž ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… 객체인 User.prototype을 μ‚¬μš©ν•˜μ—¬ λ©”μ†Œλ“œλ₯Ό ν•œλ²ˆ μ •μ˜ν•΄λ³΄λ„λ‘ ν•˜μž. thisλ₯Ό ν†΅ν•΄μ„œ μ •μ˜ν•˜λŠ” 방법과 μ–΄λ–€ 차이가 μžˆμ„κΉŒ?

    function User (name) {}
    User.prototype.say = function () {
      console.log('Hello, World!');
    }
    
    const evan = new User();
    console.log(evan.say());
    Hello, World!

    일단 thisλ₯Ό μ‚¬μš©ν•˜μ—¬ μ •μ˜ν–ˆλ˜ λ©”μ†Œλ“œμ™€ λ™μΌν•œ λŠλ‚ŒμœΌλ‘œ μž‘λ™ν•˜κ³  μžˆλ‹€. κ·Έλž˜μ„œ λ™μΌν•œ λ™μž‘μ΄λΌκ³  생각할 μˆ˜λ„ μžˆμ§€λ§Œ, 사싀 두 방법듀 μ‚¬μ΄μ—λŠ” μ€‘μš”ν•œ 차이가 μ‘΄μž¬ν•œλ‹€.

    λ°”λ‘œ μƒμ„±μž ν•¨μˆ˜λ₯Ό 톡해 μƒμ„±λœ λͺ¨λ“  객체듀이 ν•΄λ‹Ή λ©”μ†Œλ“œλ₯Ό κ³΅μœ ν•˜κ³  μžˆλƒ, μ—†λƒμ˜ 차이이닀. 이전과 λ§ˆμ°¬κ°€μ§€λ‘œ 두 개의 객체λ₯Ό μƒμ„±ν•˜κ³ , 두 객체의 λ©”μ†Œλ“œλ₯Ό λΉ„κ΅ν•΄λ³΄μž.

    const evan = new User();
    const john = new User();
    
    console.log(evan.say === john.say);
    true

    음? μ΄λ²ˆμ—λŠ” μ•„κΉŒμ™€λŠ” λ‹€λ₯΄κ²Œ 두 객체의 λ©”μ†Œλ“œκ°€ κ°™λ‹€κ³  ν•œλ‹€. 방금 μ „κ³ΌλŠ” λ‹€λ₯΄κ²Œ μ΄λ²ˆμ—λŠ” evan.say와 john.sayκ°€ 객체에 λ”°λ‘œλ”°λ‘œ μ •μ˜λœ λ©”μ†Œλ“œκ°€ μ•„λ‹Œ, 원본 객체의 λ©”μ†Œλ“œλ₯Ό κ³΅μœ ν•˜κ³  μžˆλŠ” 상황이기 λ•Œλ¬Έμ΄λ‹€.

    μƒμ„±λœ evan 객체λ₯Ό ν•œλ²ˆ μ½˜μ†”μ— 좜λ ₯해보면, 원본 객체의 ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλ₯Ό κ³΅μœ ν•˜κ³  μžˆλ‹€λŠ” 말이 무엇인지 μ•Œ 수 μžˆλ‹€.

    console.log(evan);
    User {}

    evan 객체λ₯Ό 좜λ ₯ν•΄λ³΄λ‹ˆ, 이 κ°μ²΄λŠ” 아무 λ©”μ†Œλ“œλ‚˜ ν”„λ‘œνΌν‹°λ„ κ°€μ§€κ³  μžˆμ§€ μ•Šκ³  ν…… λΉ„μ–΄μžˆλŠ” μΉœκ΅¬λ‹€.

    즉, μƒμ„±μž ν•¨μˆ˜ λ‚΄μ—μ„œ thisλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³ , 원본 객체에 λ©”μ†Œλ“œλ‚˜ ν”„λ‘œνΌν‹°λ₯Ό μ •μ˜ν•˜κ²Œ 되면 κ°μ²΄λ“€μ—κ²ŒλŠ” ν•΄λ‹Ή ν”„λ‘œνΌν‹°κ°€ μ—†κ³ , 원본 객체의 ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλ₯Ό μ°Έμ‘°ν•œλ‹€λŠ” 것이닀.

    이 νŠΉμ§•μ„ μ œλŒ€λ‘œ μΈμ§€ν•˜μ§€ λͺ»ν•˜λ©΄ 이런 상황도 λ°œμƒν•  수 μžˆλ‹€.

    User.prototype.name = 'Evan';
    
    console.log(evan.name);
    console.log(john.name);
    Evan
    Evan

    κ·Έλ ‡κΈ° λ•Œλ¬Έμ— 각 κ°μ²΄λ§ˆλ‹€ κ³ μœ ν•œ ν”„λ‘œνΌν‹°λ₯Ό λΆ€μ—¬ν•˜κ³  μ‹Άλ‹€λ©΄ 원본 객체에 μ •μ˜ν•˜λŠ” 것이 μ•„λ‹ˆλΌ, μƒμ„±μž ν•¨μˆ˜ λ‚΄μ—μ„œ thisλ₯Ό μ‚¬μš©ν•˜μ—¬ μ •μ˜ν•΄μ•Όν•œλ‹€. λ‹€μ‹œ λ§ν•˜μ§€λ§Œ 원본 객체에 μ •μ˜ν•œ ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλŠ” μƒμ„±λœ 객체듀 끼리 κ³΅μœ λœλ‹€.

    ν•œ κ°€μ§€ μ΄μƒν•œ 점은, λΆ„λͺ…νžˆ evan κ°μ²΄μ—λŠ” μ•„λ¬΄λŸ° ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλ„ μ—†μ—ˆλŠ”λ°, ν•„μžλŠ” λΆ„λͺ…νžˆ evan.sayλ₯Ό 톡해 ν•΄λ‹Ή λ©”μ†Œλ“œμ— μ ‘κ·Όν•  수 μžˆμ—ˆλ‹€λŠ” 것이닀. μ–΄λ–»κ²Œ 이런 일이 κ°€λŠ₯ν•œ κ²ƒμΌκΉŒ?

    ν”„λ‘œν† νƒ€μž… 룩업

    κ·Έ μ§ˆλ¬Έμ— λŒ€ν•œ 해닡은 λ°”λ‘œ μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ 객체 λ‚΄μ—μ„œ ν”„λ‘œνΌν‹°λ₯Ό μ°ΎλŠ” 방법 쀑 ν•˜λ‚˜μΈ ν”„λ‘œν† νƒ€μž… 룩업(Prototype Lookup)μ—μ„œ μ•Œμ•„λ³Ό 수 μžˆλ‹€. 방금 μ „ μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ evan κ°μ²΄μ—μ„œ say λ©”μ†Œλ“œλ₯Ό μ°Ύμ•„λƒˆλ˜ 과정은 λ‹€μŒκ³Ό κ°™λ‹€.

    prototype lookup
    1. evan.say둜 μ ‘κ·Ό μ‹œλ„
    2. μ–΄, say ν”„λ‘œνΌν‹°κ°€ μ—†λ„€? __proto__λ₯Ό 톡해 원본 객체둜 μ˜¬λΌκ°€λ³΄μž!
    3. User.prototype객체야, λ„ˆλŠ” say ν”„λ‘œνΌν‹° κ°€μ§€κ³  μžˆλ‹ˆ?
    4. μžˆλ„€? Profit!

    이런 μ‹μœΌλ‘œ μš°λ¦¬κ°€ μ–΄λ–€ 객체의 ν”„λ‘œνΌν‹°μ— 접근을 μ‹œλ„ν–ˆμ„ λ•Œ, μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” λ¨Όμ € κ·Έ 객체가 ν•΄λ‹Ή ν”„λ‘œνΌν‹°λ₯Ό κ°€μ§€κ³  μžˆλŠ”μ§€λ₯Ό ν™•μΈν•˜κ³ , ν•΄λ‹Ή ν”„λ‘œνΌν‹°κ°€ μ—†λ‹€λ©΄ κ·Έ 객체의 원본 객체둜 거슬러 μ˜¬λΌκ°€μ„œ λ‹€μ‹œ ν™•μΈν•˜κ²Œ λœλ‹€.

    이 μ§‘μš”ν•œ 확인 과정은 λͺ¨λ“  객체의 쑰상인 Object.prototype에 λ‹€λ‹€λ₯Ό λ•ŒκΉŒμ§€ κ³„μ†λ˜κ³ , λ§Œμ•½ 여기에도 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” ν”„λ‘œνΌν‹°λΌλ©΄ κ·Έλ•Œμ„œμ•Ό undefinedλ₯Ό λ°˜ν™˜ν•˜κ²Œ λœλ‹€.

    이 말인 μ¦‰μŠ¨, λͺ¨λ“  κ°μ²΄λŠ” μžμ‹ μ˜ ν”„λ‘œν† νƒ€μž… 체인 내에 μžˆλŠ” λͺ¨λ“  원본 κ°μ²΄λ“€μ˜ ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œμ— μ ‘κ·Όν•  수 μžˆλ‹€λŠ” λœ»μ΄λ‹€.

    μ‰½κ²Œ 말해, 방금 μƒμ„±ν•œ evan κ°μ²΄λŠ” 아무 ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œλ„ κ°€μ§€κ³  μžˆμ§€ μ•Šμ§€λ§Œ, μžμ‹ μ˜ 원본 객체인 User.prorotype에 μ •μ˜λœ say λ©”μ†Œλ“œλ„ μ‚¬μš©ν•  수 있고, Object.prototype에 μžˆλŠ” toStringμ΄λ‚˜ hasOwnProperty와 같은 λ©”μ†Œλ“œλ„ μ‚¬μš©ν•  수 μžˆλ‹€λŠ” 것이닀.

    evan 객체는 프토토타입 체인 내에 있는 모든 원본 객체의 프로퍼티를 공유받는다

    이 ν”„λ‘œν† νƒ€μž… 룩업 과정은 객체의 ν”„λ‘œνΌν‹°λ‚˜ λ©”μ†Œλ“œμ— μ ‘κ·Όν•˜λŠ” κ·Έ μˆœκ°„λ§ˆλ‹€ μˆ˜ν–‰λ˜κΈ° λ•Œλ¬Έμ—, ν΄λž˜μŠ€κ°€ μ •μ˜λ  λ•Œ λͺ¨λ“  상속관계가 ν•¨κ»˜ ν‰κ°€λ˜λŠ” 클래슀 기반 μ–Έμ–΄μ˜ μƒμ†κ³ΌλŠ” 쑰금 λ‹€λ₯Έ λŠλ‚Œμ΄λ‹€.

    κ·ΈλŸ¬λ‚˜ μΆ”μƒμ μœΌλ‘œ 생각해보면 원본 객체(λΆ€λͺ¨)의 속성을 λ¬Όλ €λ°›κ³  μžˆλ‹€λŠ” μ μ—μ„œ μ°©μ•ˆν•˜μ—¬, ν”„λ‘œν† νƒ€μž… 룩업을 ν† λŒ€λ‘œ 상속을 κ΅¬ν˜„ν•  수 μžˆλ‹€.

    ν”„λ‘œν† νƒ€μž…μ„ μ‚¬μš©ν•œ 상속

    μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ ν”„λ‘œν† νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ 상속을 κ΅¬ν˜„ν•˜λŠ” 방법은 크게 Object.create λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 방법과 이 λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€μ•ŠλŠ” (λ”λŸ¬μš΄) 방법, 두 κ°€μ§€λ‘œ λ‚˜λˆ„μ–΄μ§ˆ 수 μžˆλ‹€.

    사싀 Object.create만 μ‚¬μš©ν•΄λ„ ν”„λ‘œν† νƒ€μž…μ„ μ‚¬μš©ν•œ 상속은 μΆ©λΆ„νžˆ κ΅¬ν˜„μ΄ κ°€λŠ₯ν•˜λ‹€. ν•˜μ§€λ§Œ ꡳ이 두 κ°€μ§€λ₯Ό λ‚˜λˆ μ„œ μ΄μ•ΌκΈ°ν•œ μ΄μœ λŠ”, Object.create λ©”μ†Œλ“œκ°€ Internet Explorer 9λΆ€ν„° 지원이 되기 λ•Œλ¬Έμ΄λ‹€.

    ν•˜μ§€λ§Œ ν•„μžλŠ” ν•„μžμ˜ 행볡을 μœ„ν•΄ μ“°λŠ” ν¬μŠ€νŒ…μ—μ„œ IE 8 μ΄ν•˜ ν™˜κ²½μ— λŒ€ν•œ μžμ„Έν•œ μ΄μ•ΌκΈ°λŠ” λ³„λ‘œ ν•˜κ³  μ‹Άμ§€ μ•ŠμœΌλ―€λ‘œ Object.createλ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 방법에 λŒ€ν•œ μ½”λ“œλ₯Ό κ°„λ‹¨ν•˜κ²Œ ν•„μžμ˜ Github Gist 링크둜 μ²¨λΆ€ν•˜κ² λ‹€.

    Object.createλ₯Ό μ‚¬μš©ν•˜μž

    Object.create λ©”μ†Œλ“œλŠ” 첫 번째 인자둜 생성할 객체의 원본 객체가 될 객체, 두 번째 인자둜 μƒˆλ‘œ 생성할 객체에 μΆ”κ°€ν•  ν”„λ‘œνΌν‹°λ₯Ό 객체 νƒ€μž…μœΌλ‘œ λ°›λŠ”λ‹€.

    Object.create(proto: Object, properties?: Object);

    μ΄λ•Œ 두 번째 μΈμžλŠ” 선택사항이며, λ‹¨μˆœν•˜κ²Œ { test: 1 }처럼 λ„˜κΈ°λŠ” 것이 μ•„λ‹ˆλΌ, Object.defineProperties λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•  λ•Œ 처럼 데이터 μ„œμˆ μžμ™€ μ ‘κ·Ό μ„œμˆ μžλ₯Ό μ§€μ •ν•΄μ€˜μ•Όν•œλ‹€.

    Object.create(User.prototype, {
      foo: {
        configurable: false,
        enumerable: true,
        value: 'I am Foo!',
      }
    });

    μžμ„Έν•œ ν”„λ‘œνΌν‹°λ“€μ˜ μ˜λ―ΈλŠ” MDN Web Docs: Object.definePropertiesμ—μ„œ 확인해보도둝 ν•˜μž.

    이 λ©”μ†Œλ“œμ—μ„œ μ€‘μš”ν•œ ν¬μΈνŠΈλŠ” 객체의 ν”„λ‘œν† νƒ€μž… 객체λ₯Ό μ§€μ •ν•  수 μžˆλ‹€λŠ” 것이며, 이 말인 μ¦‰μŠ¨ 객체의 ν”„λ‘œν† νƒ€μž… 체인을 λ‚΄ λ§˜λŒ€λ‘œ λ§Œμ Έμ€„ 수 μžˆλ‹€λŠ” 것이닀. 심지어 λ™μ μœΌλ‘œ 변경도 κ°€λŠ₯ν•˜λ‹€.(사싀 이게 JS의 λ³€νƒœμ μΈ 면…)

    그럼 이제 Object.create λ©”μ†Œλ“œμ™€ ν”„λ‘œν† νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ 상속을 ν•œλ²ˆ κ΅¬ν˜„ν•΄λ³΄λ„λ‘ ν•˜μž.

    function SuperClass (name) {
      this.name = name;
    }
    SuperClass.prototype.say = function () {
      console.log(`I am ${this.name}`);
    }

    μš°μ„  λΆ€λͺ¨ 클래슀 역할을 ν•  SuperClass μƒμ„±μž ν•¨μˆ˜λ₯Ό μƒμ„±ν•˜κ³ , 이 ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… 객체에 say λ©”μ†Œλ“œλ₯Ό μ •μ˜ν–ˆλ‹€. 그럼 이제 μžμ‹ 클래슀 역할을 ν•  μƒμ„±μž ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•˜κ³ , 이 두 개의 ν•¨μˆ˜μ˜ 상속 관계도 ν•¨κ»˜ μ •μ˜ν•΄λ³΄μž.

    function SubClass (name) {
      SuperClass.call(this, name);
    }
    SubClass.prototype = Object.create(SuperClass.prototype);
    SubClass.prototype.constructor = SubClass;
    SubClass.prototype.run = function () {
      console.log(`${this.name} is running`);
    }

    뭘 이것저것 많이 λ§Œμ§„ 것 κ°™μ§€λ§Œ, 막상 ν•˜λ‚˜ν•˜λ‚˜ λœ―μ–΄λ³΄λ©΄ 별 κ±° μ—†λ‹€.

    SuperClass.call(this) Function.prototype.call λ©”μ†Œλ“œλŠ” 호좜된 ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλ₯Ό 첫 번째 인자둜 받은 λ…€μ„μœΌλ‘œ λ³€κ²½ν•œλ‹€. 즉, this의 νƒ€κ²Ÿμ„ λ³€κ²½ν•˜λŠ” 것이닀.

    즉, SuperClass.call(this, name)의 μ˜λ―ΈλŠ” λΆ€λͺ¨ μƒμ„±μž ν•¨μˆ˜μ˜ μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜λ˜, μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλ₯Ό μžμ‹ μƒμ„±μž ν•¨μˆ˜λ‘œ λ³€κ²½ν•˜λΌλŠ” μ˜λ―Έμ΄λ‹€. μžλ°”λ‘œ 치면 super λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” 것과 λΉ„μŠ·ν•œ λŠλ‚Œμ΄λž„κΉŒ.

    ν•„μžλŠ” μ΄λ•Œ call λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν–ˆμ§€λ§Œ, 뭐가 됐든 λΆ€λͺ¨ μƒμ„±μž ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλ§Œ λ³€κ²½ν•΄μ£Όλ©΄ μž₯땑이기 λ•Œλ¬Έμ— applyλ‚˜ bind λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•΄λ„ 상관없닀.

    SubClass.prototype λ³€κ²½ κ·Έ ν›„ Object.create λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ SuperClass.prototype 객체λ₯Ό 원본 객체둜 ν•˜λŠ” μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•˜κ³ , 이 객체λ₯Ό SubClass의 ν”„λ‘œν† νƒ€μž… 객체둜 ν• λ‹Ήν•΄μ€€λ‹€. μžμ‹ μƒμ„±μž ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… 객체와 λΆ€λͺ¨ μƒμ„±μž ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… 객체 κ°„μ˜ ν”„λ‘œν† νƒ€μž… 체인, μ‰½κ²Œ 말해 λΆ€λͺ¨ μžμ‹ 관계λ₯Ό λ§Œλ“€μ–΄ μ£ΌλŠ” 것이닀.

    SubClass.prorotype.constructor λ³€κ²½ μš°λ¦¬λŠ” λΆ€λͺ¨ μƒμ„±μž ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… 객체λ₯Ό 토씨 ν•˜λ‚˜ μ•ˆλ°”κΎΈκ³  κ·ΈλŒ€λ‘œ λ³΅μ œν–ˆκΈ° λ•Œλ¬Έμ—, μƒˆλ‘­κ²Œ μƒμ„±ν•œ μžμ‹ μƒμ„±μž ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… 객체의 constructor ν”„λ‘œνΌν‹°λŠ” μ—¬μ „νžˆ λΆ€λͺ¨ μƒμ„±μž ν•¨μˆ˜μΈ SuperClassλ₯Ό μ°Έμ‘°ν•˜κ³  μžˆλ‹€.

    ν•˜μ§€λ§Œ μžμ‹ μƒμ„±μž ν•¨μˆ˜μΈ SubClassλ₯Ό 톡해 μƒμ„±λœ 객체가 SuperClassλ₯Ό μ‚¬μš©ν•˜μ—¬ μƒμ„±λœ κ²ƒμ²˜λŸΌ 처리되면 μ•ˆλ˜λ―€λ‘œ, λ‹€μ‹œ constructor ν”„λ‘œνΌν‹°λ₯Ό SubClass둜 λ³€κ²½ν•΄μ€˜μ•Όν•œλ‹€.

    이런 과정듀을 거치면 λ‹€μŒκ³Ό 같은 관계가 μ„±λ¦½λœλ‹€.

    extends

    이제 ν•œλ²ˆ SubClass μƒμ„±μž ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 객체λ₯Ό 생성해보고, μ œλŒ€λ‘œ λΆ€λͺ¨ μƒμ„±μž ν•¨μˆ˜μ˜ 속성듀을 λ¬Όλ €λ°›μ•˜λŠ”μ§€ ν™•μΈν•΄λ³΄μž.

    const evan = new SubClass('Evan');
    console.log(evan);
    console.log(evan.__proto__);
    console.log(evan.__proto__.__proto__)
    SubClass { name: 'Evan' } // μ—λ°˜ 객체
    SubClass { constructor: [Function: SubClass], run: [Function] } // μ—λ°˜ 객체의 원본 객체
    SuperClass { say: [Function] } // μ—λ°˜ 객체의 원본 객체의 원본 객체

    evan κ°μ²΄λŠ” SubClass의 ν”„λ‘œν† νƒ€μž… 객체λ₯Ό λ³΅μ œν•΄μ„œ μ •μƒμ μœΌλ‘œ μƒμ„±λ˜μ—ˆκ³ , evan 객체의 원본 객체와 원본 객체의 원본 객체도 잘 μ²΄μ΄λ‹λ˜μ–΄μžˆλ‹€.

    즉, evan -> SubClass.prototype -> SuperClass.prototype으둜 μ΄μ–΄μ§€λŠ” ν”„λ‘œν† νƒ€μž… 체인이 μ™„μ„±λœ 것이닀. μ΄λ•Œ evan 객체의 runμ΄λ‚˜ say λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄, μœ„μ—μ„œ μ–ΈκΈ‰ν•œ ν”„λ‘œν† νƒ€μž… 룩업을 톡해 원본 객체의 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€.

    마치며

    이전 ν¬μŠ€νŒ…μ— 이어 μ΄λ²ˆμ—λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ ν”„λ‘œν† νƒ€μž…μ„ ν™œμš©ν•œ 상속 νŒ¨ν„΄μ— λŒ€ν•œ λ‚΄μš©μ„ ν•œλ²ˆ λ‹€λ€„λ³΄μ•˜λ‹€.

    μ†”μ§νžˆ λ§ν•΄μ„œ, ν•„μžκ°€ μ‹€λ¬΄μ—μ„œ μ΄λŸ¬ν•œ νŒ¨ν„΄μ„ μ‚¬μš©ν•΄μ„œ 상속을 κ΅¬ν˜„ν•΄λ³Έ κ²½ν—˜μ€ 거의 μ—†λ‹€. ν•„μžκ°€ 개발자둜 일을 μ‹œμž‘ν•˜κ³  μ–Όλ§ˆ λ˜μ§€ μ•Šμ•„ ES6κ°€ λ‚˜μ˜€κΈ°λ„ ν–ˆμ—ˆκ³ , ν•„μžλŠ” λ‹Ήμ‹œ μžλ°”κ°€ 더 μ΅μˆ™ν–ˆκΈ° λ•Œλ¬Έμ— μƒˆλ‘œ μΆ”κ°€λœ class ν‚€μ›Œλ“œμ— 흠뻑 λΉ μ Έμžˆμ—ˆλ‹€.

    ν•˜μ§€λ§Œ 일을 μ‹œμž‘ν•˜κ³  λͺ‡ 년이 μ§€λ‚˜λ©΄μ„œ λ ˆκ±°μ‹œ μ½”λ“œμ—μ„œ 이 상속 νŒ¨ν„΄μ„ κ½€ λ§ˆμ£ΌμΉ˜κΈ°λ„ ν–ˆκ³ , λ©΄μ ‘μ—μ„œ 이런 νŒ¨ν„΄μ— λŒ€ν•΄μ„œ λ¬Όμ–΄λ³΄λŠ” κ²½μš°λ„ μžˆμ—ˆκΈ° λ•Œλ¬Έμ— ν™•μ‹€νžˆ 곡뢀할 ν•„μš”λŠ” μžˆλŠ” 것 κ°™λ‹€.

    아무리 μš”μ¦˜ ES5λ₯Ό 거의 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€κ³  ν•˜μ§€λ§Œ, 사싀 이런 상속 νŒ¨ν„΄μ΄ μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•œ ν”„λ‘œκ·Έλž¨ μ•„ν‚€ν…μ²˜μ˜ 근간이기도 ν•˜λ‹ˆ 말이닀.

    μ΄μƒμœΌλ‘œ ν”„λ‘œν† νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ μƒμ†ν•˜κΈ° ν¬μŠ€νŒ…μ„ λ§ˆμΉœλ‹€.

    Evan Moon

    🐒 거뢁이처럼 μ‚΄μž

    κ°œλ°œμ„ μž˜ν•˜κΈ° μœ„ν•΄μ„œκ°€ μ•„λ‹Œ κ°œλ°œμ„ 즐기기 μœ„ν•΄ λ…Έλ ₯ν•˜λŠ” κ°œλ°œμžμž…λ‹ˆλ‹€. μ‚¬μ†Œν•œ 생각 정리뢀터 νŠœν† λ¦¬μ–Ό, μ‚½μ§ˆκΈ° 정도λ₯Ό 주둜 끄적이고 μžˆμŠ΅λ‹ˆλ‹€.