관리 메뉴

Daehyunii's Dev-blog

19μž₯ ν”„λ‘œν† νƒ€μž… λ³Έλ¬Έ

πŸ“š Language & CS knowledge/JavaScript (λͺ¨λ˜μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive)

19μž₯ ν”„λ‘œν† νƒ€μž…

Daehyunii 2022. 7. 13. 22:25

  μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” ν”„λ‘œν† νƒ€μž… 기반의 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄λ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 객체 기반의 ν”„λ‘œκ·Έλž˜λ° 언어이며 μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό 이루고 μžˆλŠ” 거의 'λͺ¨λ“  것'이 객체닀.(μ›μ‹œ νƒ€μž…μ˜ κ°’ μ œμ™Έ)

 

19.1 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ° 

  객체지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ€ ν”„λ‘œκ·Έλž¨μ„ λͺ…λ Ήμ–΄ λ˜λŠ” ν•¨μˆ˜μ˜ λͺ©λ‘μœΌλ‘œ λ³΄λŠ” 전톡적인 λͺ…λ Ήν˜• ν”„λ‘œκ·Έλž˜λ°μ˜ μ ˆμ°¨μ§€ν–₯적 κ΄€μ μ—μ„œ λ²—μ–΄λ‚˜ μ—¬λŸ¬ 개의 독립적 λ‹¨μœ„, 즉 객체의 μ§‘ν•©μœΌλ‘œ ν”„λ‘œκ·Έλž¨μ„ ν‘œν˜„ν•˜λ €λŠ” ν”„λ‘œκ·Έλž˜λ° νŒ¨λŸ¬λ‹€μž„μ„ λ§ν•œλ‹€. κ°μ²΄λž€, 속성을 톡해 μ—¬λŸ¬ 개의 값을 ν•˜λ‚˜μ˜ λ‹¨μœ„λ‘œ κ΅¬μ„±ν•œ 볡합적인 자료ꡬ쑰이며, 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ€ 독립적인 객체의 μ§‘ν•©μœΌλ‘œ ν”„λ‘œκ·Έλž¨μ„ ν‘œν˜„ν•˜λ €λŠ” ν”„λ‘œκ·Έλž˜λ° νŒ¨λŸ¬λ‹€μž„μ΄λ‹€. 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ€ 객체의 μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 데이터, ν”„λ‘œνΌν‹°μ™€ μƒνƒœ 데이터λ₯Ό μ‘°μž‘ν•  수 μžˆλŠ” λ™μž‘, λ©”μ„œλ“œλ₯Ό ν•˜λ‚˜μ˜ 논리적인 λ‹¨μœ„λ‘œ λ¬Άμ–΄ μƒκ°ν•œλ‹€. λ”°λΌμ„œ 볡합적인 자료ꡬ쑰라고 ν•  수 μžˆλ‹€. 각 κ°μ²΄λŠ” 고유의 κΈ°λŠ₯을 κ°–λŠ” 독립적인 λΆ€ν’ˆμœΌλ‘œ λ³Ό 수 μžˆμ§€λ§Œ κ³ μœ ν•œ κΈ°λŠ₯을 μˆ˜ν–‰ν•˜λ©΄μ„œ λ‹€λ₯Έ 객체와 관계성을 κ°€μ§ˆ 수 μžˆλ‹€. λ‹€λ₯Έ 객체와 λ©”μ‹œμ§€λ₯Ό μ£Όκ³  λ°›κ±°λ‚˜ 데이터λ₯Ό μ²˜λ¦¬ν•  μˆ˜λ„ μžˆλ‹€. λ˜λŠ” λ‹€λ₯Έ 객체의 μƒνƒœ λ°μ΄ν„°λ‚˜ λ™μž‘μ„ 상속받아 μ‚¬μš©ν•˜κΈ°λ„ ν•œλ‹€.

 

19.2 상속과 ν”„λ‘œν† νƒ€μž…

  상속은 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ˜ 핡심 κ°œλ…μœΌλ‘œ, μ–΄λ–€ 객체의 ν”„λ‘œνΌν‹° λ˜λŠ” λ©”μ„œλ“œλ₯Ό λ‹€λ₯Έ 객체가 상속받아 κ·ΈλŒ€λ‘œ μ‚¬μš©ν•  수 μžˆλŠ” 것을 λ§ν•œλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” ν”„λ‘œν† νƒ€μž…μ„ 기반으둜 상속을 κ΅¬ν˜„ν•˜μ—¬ 기쑴의 μ½”λ“œλ₯Ό 적극적으둜 μž¬μ‚¬μš©ν•΄ λΆˆν•„μš”ν•œ 쀑볡을 μ œκ±°ν•œλ‹€. 

function Circle(radius){
    this.radius = radius;
    this.getArea = function(){
        return Math.PI * this.radius ** 2;
    };
}

const circle1 = new Circle(1);
const circle2 = new Circle(2);

console.log(circle1.getArea === circle2.getArea) // false

console.log(circle1.getArea()); // 3.141592653589793
console.log(circle2.getArea()); // 12.566370614359172

console.log(circle1); // Circle {radius: 1, getArea: ƒ}
console.log(circle2); // Circle {radius: 2, getArea: ƒ}

  μœ„μ˜ μ½”λ“œλ₯Ό 보면 μƒμ„±μž ν•¨μˆ˜λ₯Ό 톡해 circle1, circle2 객체λ₯Ό μƒμ„±ν–ˆλ‹€. 각각의 μΈμŠ€ν„΄μŠ€λŠ” ν”„λ‘œνΌν‹° 값은 λ‹€λ₯΄μ§€λ§Œ λ™μΌν•œ getArea λ©”μ„œλ“œλ₯Ό 각자 가지고 μžˆλ‹€. μ΄λŠ” λ©”λͺ¨λ¦¬λ₯Ό λΆˆν•„μš”ν•˜κ²Œ λ‚­λΉ„ν•œλ‹€. getArea λ©”μ„œλ“œλŠ” μΈμŠ€ν„΄μŠ€λ“€μ΄ λ™μΌν•œ λ‚΄μš©μ˜ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ―€λ‘œ 단 ν•˜λ‚˜λ§Œ μƒμ„±ν•˜μ—¬ λͺ¨λ“  μΈμŠ€ν„΄μŠ€κ°€ κ³΅μœ ν•΄μ„œ μ‚¬μš©ν•˜λŠ” 것이 λ°”λžŒμ§ν•˜λ‹€. μ΄λŠ” 상속을 톡해 ν•΄κ²°ν•  수 μžˆλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” ν”„λ‘œν† νƒ€μž…μ„ 기반으둜 상속을 κ΅¬ν˜„ν•œλ‹€.

function Circle(radius){
    this.radius = radius;
}

Circle.prototype.getArea = function(){
    return Math.PI * this.radius ** 2
};

const circle1 = new Circle(1);
const circle2 = new Circle(2);

console.log(circle1.getArea === circle2.getArea) // true

console.log(circle1.getArea()); // 3.141592653589793
console.log(circle2.getArea()); // 12.566370614359172
console.log(circle1); // Circle {radius: 1}
console.log(circle2); // Circle {radius: 2}

  μœ„μ˜ μ½”λ“œμ²˜λŸΌ Circle μƒμ„±μž ν•¨μˆ˜κ°€ μƒμ„±ν•œ 객체듀은 Circle.prototype을 ν”„λ‘œν† νƒ€μž…μœΌλ‘œ κ°–κ³ , μƒμœ„ 객체인 Circle.prototype의 λͺ¨λ“  ν”„λ‘œνΌν‹°μ™€ λ©”μ„œλ“œλ₯Ό μƒμ†λ°›λŠ”λ‹€. κ·ΈλŸ¬λ―€λ‘œ Circle.prototype에 getArea λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜μ—¬ ν•˜μœ„ 객체듀이 λͺ¨λ‘ μ‚¬μš©ν•  수 있게 λ§Œλ“€μ–΄ μ½”λ“œμ˜ 쀑볡을 μ œκ±°ν•  수 μžˆλ‹€.

 

19.3 ν”„λ‘œν† νƒ€μž… 객체

  ν”„λ‘œν† νƒ€μž… κ°μ²΄λž€ 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ˜ 근간을 μ΄λ£¨λŠ” 객체 κ°„ 상속을 κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λœλ‹€. ν”„λ‘œν† νƒ€μž…μ€ μ–΄λ–€ 객체의 λΆ€λͺ¨ 객체의 역할을 ν•˜λŠ” κ°μ²΄λ‘œμ„œ λ‹€λ₯Έ 객체에 곡유 ν”„λ‘œνΌν‹°λ₯Ό μ œκ³΅ν•œλ‹€. ν”„λ‘œν† νƒ€μž…μ„ 상속받은 μžμ‹ κ°μ²΄λŠ” λΆ€λͺ¨ 객체의 ν”„λ‘œνΌν‹°λ₯Ό μžμ‹ μ˜ ν”„λ‘œνΌν‹°μ²˜λŸΌ 자유둭게 μ‚¬μš©ν•  수 μžˆλ‹€. λͺ¨λ“  κ°μ²΄λŠ” [[Prototype]] μ΄λΌλŠ” λ‚΄λΆ€ μŠ¬λ‘―μ„ 가지며, 이 λ‚΄λΆ€ 슬둯의 값은 ν”„λ‘œν† νƒ€μž…μ˜ μ°Έμ‘°λ‹€.

 

  [[Protoype]]에 μ €μž₯λ˜λŠ” ν”„λ‘œν† νƒ€μž…μ€ 객체 생성 방식에 μ˜ν•΄ κ²°μ •λœλ‹€. 즉, 객체가 μƒμ„±λ λ•Œ 객체 생성 방식에 따라 ν”„λ‘œν† νƒ€μž…μ΄ κ²°μ •λ˜κ³  [[Prototype]]에 μ €μž₯λœλ‹€. λͺ¨λ“  κ°μ²΄λŠ” ν•˜λ‚˜μ˜ ν”„λ‘œν† νƒ€μž…μ„ κ°–λŠ”λ‹€. 그리고 λͺ¨λ“  ν”„λ‘œν† νƒ€μž…μ€ μƒμ„±μž ν•¨μˆ˜μ™€ μ—°κ²°λ˜μ–΄ μžˆλ‹€. 즉, 객체와 ν”„λ‘œν† νƒ€μž…κ³Ό μƒμ„±μž ν•¨μˆ˜λŠ” μ„œλ‘œ μ—°κ²°λ˜μ–΄ μžˆλ‹€. 객체의 [[Prototype]] λ‚΄λΆ€ μŠ¬λ‘―μ—λŠ” 직접 μ ‘κ·Όν•  수 μ—†μ§€λ§Œ, __proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 객체 μžμ‹ μ˜ ν”„λ‘œν† νƒ€μž…, 즉 μžμ‹ μ˜ [[Prototype]] λ‚΄λΆ€ 슬둯이 κ°€λ¦¬ν‚€λŠ” ν”„λ‘œν† νƒ€μž…μ— κ°„μ ‘μ μœΌλ‘œ μ ‘κ·Όν•  수 μžˆλ‹€. 그리고 ν”„λ‘œν† νƒ€μž…μ€ μžμ‹ μ˜ constructor ν”„λ‘œνΌν‹°λ₯Ό 톡해 μƒμ„±μž ν•¨μˆ˜μ— μ ‘κ·Όν•  수 있고, μƒμ„±μž ν•¨μˆ˜λŠ” μžμ‹ μ˜ prototype ν”„λ‘œνΌν‹°λ₯Ό 톡해 ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•  수 μžˆλ‹€. 

 

  이 뢀뢄이 κ³΅λΆ€ν•˜λ©΄μ„œ κ°€μž₯ ν—·κ°ˆλ Έλ˜ 뢀뢄이닀. 이걸 개발자의 κ΄€μ μ—μ„œ 바라보면 이해가 쑰금 더 μ‰¬μšΈ 수 μžˆλ‹€. 개발자의 κ΄€μ μ—μ„œ 보자면 ν”„λ‘œν† νƒ€μž…μ˜ 속성듀은 ν•˜μœ„ 객체가 λ‹€ μ‚¬μš©ν•  수 μžˆλ‹€. κ·Έλ ‡λ‹€λ©΄ 'ν”„λ‘œν† νƒ€μž…μ˜ λ‚΄μš©μ„ ν™•μΈν•˜κ±°λ‚˜, λ‚΄μš©μ„ μΆ”κ°€ν•˜κ³ μž ν•œλ‹€λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Όν• κΉŒ?' 

 

1. λͺ¨λ“  ν”„λ‘œν† νƒ€μž…μ€ constructor ν”„λ‘œνΌν‹°λ₯Ό 가지며, constructor ν”„λ‘œνΌν‹°λŠ” μƒμ„±μž ν•¨μˆ˜λ₯Ό 가리킨닀.

 

2. ν”„λ‘œν† νƒ€μž…μ˜ constructor ν”„λ‘œνΌν‹°κ°€ κ°€λ¦¬ν‚€λŠ” μƒμ„±μž ν•¨μˆ˜λŠ” [[construct]] λ‚΄λΆ€ λ©”μ„œλ“œλ₯Ό κ°€μ§€λŠ” 'constructor'이기 λ•Œλ¬Έμ— prototype ν”„λ‘œνΌν‹°λ₯Ό 가진닀. 

 

3. μƒμ„±μž ν•¨μˆ˜μ˜ prototype ν”„λ‘œνΌν‹°λŠ” μƒμ„±μž ν•¨μˆ˜μ— μ˜ν•΄ 생성될 μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž…μ„ 가리킨닀. 이제 객체 μžμ‹ μ˜ ν”„λ‘œν† νƒ€μž…μ΄ λˆ„κ΅°μΈμ§€ λͺ…ν™•ν•˜κ²Œ μ•Œ 수 μžˆλ‹€. 이제 ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•˜λŠ” 방법은 2가지가 μžˆλ‹€.

 

4. 첫 번째 방법은 객체 μžμ‹ μ˜ ν”„λ‘œν† νƒ€μž…μ„ κ°€λ¦¬ν‚€λŠ” λ‚΄λΆ€ 슬둯 [[Prototype]]에 직접 μ ‘κ·Όν•  수 μ—†μœΌλ‹ˆ, __proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό μ΄μš©ν•˜μ—¬ 객체 μžμ‹ μ„ 톡해 κ°„μ ‘μ μœΌλ‘œ ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•  수 μžˆλ‹€.

function Circle(radius){
    this.radius = radius;
}

const circle1 = new Circle(1);
const circle2 = new Circle(2);

//circle1μ΄λΌλŠ” κ°μ²΄μ—μ„œ 직접 __proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•˜μ—¬ λ©”μ„œλ“œ μΆ”κ°€
circle1.__proto__.getArea = function(){
    return Math.PI * this.radius ** 2
};

console.log(circle1.getArea === circle2.getArea) // true

console.log(circle1.getArea()); // 3.141592653589793
console.log(circle2.getArea()); // 12.566370614359172
console.log(circle1); // Circle {radius: 1}
console.log(circle2); // Circle {radius: 2}

 

5. 두 번째 방법은 ν”„λ‘œν† νƒ€μž…μ΄ λˆ„κ΅°μΈμ§€ κ°œλ°œμžλŠ” μ•Œκ³  μžˆμœΌλ‹ˆ, μƒμ„±μž ν•¨μˆ˜λ₯Ό ν†΅ν•΄μ„œ ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•˜λŠ” 방법이닀. λͺ¨λ“  μƒμ„±μž ν•¨μˆ˜λŠ” prototype ν”„λ‘œνΌν‹°λ₯Ό 가지고 있고, μƒμ„±μžν•¨μˆ˜.prototype으둜 μƒμ„±μž ν•¨μˆ˜μ— μ˜ν•΄ λ―Έλž˜μ— 생성될 객체의 ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•  수 μžˆλ‹€. 

function Circle(radius){
    this.radius = radius;
}

//μƒμ„±μž ν•¨μˆ˜μ˜ prototype ν”„λ‘œνΌν‹°λ₯Ό 톡해 Circle μƒμ„±μž ν•¨μˆ˜κ°€ 생성할 객체의 ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Ό
Circle.prototype.getArea = function(){
    return Math.PI * this.radius ** 2
};

const circle1 = new Circle(1);
const circle2 = new Circle(2);

console.log(circle1.getArea === circle2.getArea) // true

console.log(circle1.getArea()); // 3.141592653589793
console.log(circle2.getArea()); // 12.566370614359172
console.log(circle1); // Circle {radius: 1}
console.log(circle2); // Circle {radius: 2}

 

κ°€μž₯ μ€‘μš”ν•œ 것은, 객체와 ν”„λ‘œν† νƒ€μž…κ³Ό μƒμ„±μž ν•¨μˆ˜λŠ” ν•˜λ‚˜μ˜ μ„ΈνŠΈλΌλŠ” 것이닀.(Object.prototype의 [[Prototype]]만 μ œμ™Έ)

 

19.3.1 __proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°

  λͺ¨λ“  κ°μ²΄λŠ” __proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 μžμ‹ μ˜ ν”„λ‘œν† νƒ€μž…, 즉 [[Prototype]] λ‚΄λΆ€ μŠ¬λ‘―μ— κ°„μ ‘μ μœΌλ‘œ μ ‘κ·Όν•  수 μžˆλ‹€. 

 

__proto__λŠ” μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ‹€.

  μ•žμ„œ 배웠듯이, λ‚΄λΆ€ μŠ¬λ‘―μ€ ν”„λ‘œνΌν‹°κ°€ μ•„λ‹ˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ 객체의 [[Prototype]] λ‚΄λΆ€ μŠ¬λ‘―μ—λŠ” 직접 μ ‘κ·Όν•  수 μ—†μœΌλ©°, __proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 κ°„μ ‘μ μœΌλ‘œ [[Prototype]] λ‚΄λΆ€ 슬둯의 κ°’, 즉 객체의 ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•  수 μžˆλ‹€. __proto__λŠ” Object.prototype의 μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ‹€. (이 λ˜ν•œ Object.prototype이 κ°€λ¦¬ν‚€λŠ” 객체(ν”„λ‘œν† νƒ€μž…)λ‘œλΆ€ν„° 상속받아 μ‚¬μš©ν•˜λŠ” 것이닀.)

 

__proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” 상속을 톡해 μ‚¬μš©λœλ‹€.

  __proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” 객체가 직접 μ†Œμœ ν•˜λŠ” ν”„λ‘œνΌν‹°κ°€ μ•„λ‹ˆλΌ Object.prototype의 ν”„λ‘œνΌν‹°λ‹€. λͺ¨λ“  κ°μ²΄λŠ” 상속을 톡해 Object.prototype.__proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. 즉 Object.prototype은 λͺ¨λ“  객체의 ν”„λ‘œν† νƒ€μž…μ΄λ©° Object.prototype의 __proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” λͺ¨λ“  객체가 상속받아 μ‚¬μš©ν•  수 μžˆλ‹€.

 

__proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•˜λŠ” 이유

  [[Prototype]] λ‚΄λΆ€ 슬둯의 κ°’, 즉 ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•˜κΈ° μœ„ν•΄ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” μƒν˜Έ 참쑰에 μ˜ν•΄ ν”„λ‘œν† νƒ€μž… 체인이 μƒμ„±λ˜λŠ” 것을 λ°©μ§€ν•˜κΈ° μœ„ν•΄μ„œλ‹€. ν”„λ‘œν† νƒ€μž… 체인은 단방ν–₯ λ§ν¬λ“œ 리슀트둜 κ΅¬ν˜„λ˜μ–΄μ•Ό ν•œλ‹€. κ·Έλ ‡κΈ° λ•Œλ¬Έμ— μˆœν™˜ μ°Έμ‘°(객체끼리 μ„œλ‘œκ°€ μ„œλ‘œμ˜ ν”„λ‘œν† νƒ€μž…μ΄ λ˜λŠ” 경우)ν•˜λŠ” ν”„λ‘œν† νƒ€μž… 체인이 λ§Œλ“€μ–΄μ§€λ©΄ ν”„λ‘œν† νƒ€μž… 체인 쒅점이 μ‘΄μž¬ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— ν”„λ‘œν† νƒ€μž… μ²΄μΈμ—μ„œ ν”„λ‘œνΌν‹°λ₯Ό 검색할 λ•Œ λ¬΄ν•œ 루프에 빠진닀. 이런 경우 __proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.

const child = {};
const parent = {};

child.__proto__ = parent;
parent.__proto__ = child;

/* Uncaught TypeError: Cyclic __proto__ value
at set __proto__ [as __proto__] (<anonymous>) */

19.3.2 ν•¨μˆ˜ 객체의 prototype ν”„λ‘œνΌν‹°

  ν•¨μˆ˜ 객체만이 μ†Œμœ ν•˜λŠ” prototype ν”„λ‘œνΌν‹°λŠ” μƒμ„±μž ν•¨μˆ˜κ°€ 생성할 μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž…μ„ 가리킨닀. λ”°λΌμ„œ μƒμ„±μž ν•¨μˆ˜λ‘œμ„œ ν˜ΈμΆœν•  수 μ—†λŠ” ν•¨μˆ˜, non-constructor인 ν™”μ‚΄ν‘œ ν•¨μˆ˜μ™€ ES6 λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„μœΌλ‘œ μ •μ˜ν•œ λ©”μ„œλ“œλŠ” prototype ν”„λ‘œνΌν‹°λ₯Ό μ†Œμœ ν•˜μ§€ μ•ŠμœΌλ©° ν”„λ‘œν† νƒ€μž…λ„ μƒμ„±ν•˜μ§€ μ•ŠλŠ”λ‹€. μƒμ„±μž ν•¨μˆ˜λ‘œ ν˜ΈμΆœν•˜κΈ° μœ„ν•΄ μ •μ˜ν•˜μ§€ μ•Šμ€ 일반 ν•¨μˆ˜λ„ prototype ν”„λ‘œνΌν‹°λ₯Ό μ†Œμœ ν•˜μ§€λ§Œ 객체λ₯Ό μƒμ„±ν•˜μ§€ μ•ŠλŠ” 일반 ν•¨μˆ˜μ˜ prototype ν”„λ‘œνΌν‹°λŠ” μ•„λ¬΄λŸ° μ˜λ―Έκ°€ μ—†λ‹€. κ²°κ΅­ λͺ¨λ“  객체가 Object.prototypeμœΌλ‘œλΆ€ν„° 상속받은 __proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°μ™€ ν•¨μˆ˜ 객체만이 가지고 μžˆλŠ” prototype ν”„λ‘œνΌν‹°λŠ” κ²°κ΅­ λ™μΌν•œ ν”„λ‘œν† νƒ€μž…μ„ 가리킨닀. 이듀을 μ‚¬μš©ν•˜λŠ” 주체가 λ‹€λ₯Ό 뿐이닀.

 

19.3.3 ν”„λ‘œν† νƒ€μž…μ˜ constructor ν”„λ‘œνΌν‹°μ™€ μƒμ„±μž ν•¨μˆ˜

  λͺ¨λ“  ν”„λ‘œν† νƒ€μž…μ€ constructor ν”„λ‘œνΌν‹°λ₯Ό κ°–λŠ”λ‹€. 이 ν”„λ‘œνΌν‹°λŠ” prototype ν”„λ‘œνΌν‹°λ‘œ μžμ‹ μ„ μ°Έμ‘°ν•˜κ³  μžˆλŠ” μƒμ„±μž ν•¨μˆ˜λ₯Ό 가리킨닀. 이 연결은 μƒμ„±μž ν•¨μˆ˜κ°€ 생섀될 λ•Œ, 즉 ν•¨μˆ˜ 객체가 생성될 λ•Œ 이뀄진닀. 이λ₯Ό 톡해 ν”„λ‘œν† νƒ€μž…κ³Ό μƒμ„±μž ν•¨μˆ˜κ°€ μ—°κ²° λ˜λŠ” 것이닀. 이λ₯Ό 쑰금 더 깊게 생각해 보면 νŠΉμ • 객체의 ν”„λ‘œν† νƒ€μž…μ€ constructor ν”„λ‘œνΌν‹°λ₯Ό 가지고 있고, κ°μ²΄λŠ” ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œνΌν‹°λ₯Ό 상속받아 μ‚¬μš©ν•  수 μžˆμœΌλ―€λ‘œ (κ°μ²΄μžμ‹ μ„μ°Έμ‘°.constructor)λ₯Ό 톡해 μžμ‹ μ˜ ν”„λ‘œν† νƒ€μž…κ³Ό μ—°κ²°λ˜μ–΄ μžˆλŠ” μƒμ„±μž ν•¨μˆ˜λ₯Ό μ•Œ 수 있으며, ν•΄λ‹Ή μƒμ„±μž ν•¨μˆ˜λŠ” prototype ν”„λ‘œνΌν‹°λ₯Ό 가지고 있고 ν•΄λ‹Ή (μƒμ„±μžν•¨μˆ˜.prototype)을 톡해 객체의 ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•  수 μžˆλ‹€. 

 

19.4 λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²•μ— μ˜ν•΄ μƒμ„±λœ 객체의 μƒμ„±μž ν•¨μˆ˜μ™€ ν”„λ‘œν† νƒ€μž…

  λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²•μ€ λͺ…μ‹œμ μœΌλ‘œ new μ—°μ‚°μžμ™€ ν•¨κ»˜ μƒμ„±μž ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€ μ•Šμ§€λ§Œ λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²•μ— μ˜ν•΄ μƒμ„±λœ 객체도 λ¬Όλ‘  ν”„λ‘œν† νƒ€μž…μ΄ μ‘΄μž¬ν•œλ‹€. ν•˜μ§€λ§Œ μ£Όμ˜ν•΄μ•Ό ν•  점은 λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²•μ— μ˜ν•΄ μƒμ„±λœ 객체의 경우 ν”„λ‘œν† νƒ€μž…μ˜ constructor ν”„λ‘œνΌν‹°κ°€ κ°€λ¦¬ν‚€λŠ” μƒμ„±μž ν•¨μˆ˜κ°€ λ°˜λ“œμ‹œ 객체λ₯Ό μƒμ„±ν•œ μƒμ„±μž ν•¨μˆ˜λΌκ³  단정할 수 μ—†λ‹€. 

//객체 λ¦¬ν„°λŸ΄μ— μ˜ν•œ 객체 생성과 객체의 μƒμ„±μž ν•¨μˆ˜
const child = {};

console.log(child.constructor); // ƒ Object() { [native code] }
//child 객체의 ν”„λ‘œν† νƒ€μž… constructor ν”„λ‘œνΌν‹°λ₯Ό 톡해 μƒμ„±μž ν•¨μˆ˜λ₯Ό μ•Œ 수 μžˆλ‹€.

μœ„μ˜ μ½”λ“œλ₯Ό 톡해 객체 λ¦¬ν„°λŸ΄λ‘œ μƒμ„±ν•œ 객체의 ν”„λ‘œν† νƒ€μž…μ€ Object.prototypeμ΄λΌλŠ” 것을 μ•Œ 수 μžˆλ‹€. ν•˜μ§€λ§Œ 객체 λ¦¬ν„°λŸ΄μ— μ˜ν•΄ μƒμ„±λœ κ°μ²΄λŠ” Object μƒμ„±μž ν•¨μˆ˜κ°€ μƒμ„±ν•œ 객체가 μ•„λ‹ˆλ‹€. λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²•μ— μ˜ν•΄ μƒμ„±λœ 객체도 상속을 μœ„ν•΄ ν”„λ‘œν† νƒ€μž…μ΄ ν•„μš”ν•˜λ‹€. λ”°λΌμ„œ λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²•μ— μ˜ν•΄ μƒμ„±λœ 객체도 가상적인 μƒμ„±μž ν•¨μˆ˜λ₯Ό κ°–λŠ”λ‹€. ν”„λ‘œν† νƒ€μž…μ€ μƒμ„±μž ν•¨μˆ˜μ™€ λ”λΆˆμ–΄ μƒμ„±λ˜λ©° prototypeν”„λ‘œνΌν‹°μ™€ ν”„λ‘œν† νƒ€μž…μ˜ constructor ν”„λ‘œνΌν‹°μ— μ˜ν•΄ μ—°κ²°λ˜μ–΄ 있기 λ•Œλ¬Έμ΄λ‹€. β˜…κ²°λ‘ μ μœΌλ‘œ ν”„λ‘œν† νƒ€μž…κ³Ό μƒμ„±μž ν•¨μˆ˜λŠ” λ‹¨λ…μœΌλ‘œ μ‘΄μž¬ν•  수 μ—†κ³  μ–Έμ œλ‚˜ ν•˜λ‚˜μ˜ 쌍으둜 μ‘΄μž¬ν•œλ‹€.β˜… 

 

<λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²•μ— μ˜ν•΄ μƒμ„±λœ 객체의 μƒμ„±μž ν•¨μˆ˜μ™€ ν”„λ‘œν† νƒ€μž…>

λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²• μƒμ„±μž ν•¨μˆ˜ ν”„λ‘œν† νƒ€μž…
객체 λ¦¬ν„°λŸ΄ Object Object.prototype
ν•¨μˆ˜ λ¦¬ν„°λŸ΄ Function Function.prototype
λ°°μ—΄ λ¦¬ν„°λŸ΄ Array Array.prototype
μ •κ·œ ν‘œν˜„μ‹ λ¦¬ν„°λŸ΄ RegExp RegExp.prototype

19.5 ν”„λ‘œν† νƒ€μž…μ˜ 생성 μ‹œμ 

  ν”„λ‘œν† νƒ€μž…μ€ μƒμ„±μž ν•¨μˆ˜κ°€ μƒμ„±λ˜λŠ” μ‹œμ μ— λ”λΆˆμ–΄ μƒμ„±λœλ‹€. μƒμ„±μž ν•¨μˆ˜λŠ” μ‚¬μš©μžκ°€ 직접 μ •μ˜ν•œ μ‚¬μš©μž μ •μ˜ μƒμ„±μž ν•¨μˆ˜μ™€ μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ κΈ°λ³Έ μ œκ³΅ν•˜λŠ” 빌트인 μƒμ„±μž ν•¨μˆ˜λ‘œ ꡬ뢄할 수 μžˆλ‹€.

 

19.5.1 μ‚¬μš©μž μ •μ˜ μƒμ„±μž ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… 생성 μ‹œμ 

  μƒμ„±μž ν•¨μˆ˜λ‘œμ„œ ν˜ΈμΆœν•  수 μžˆλŠ” constructor ν•¨μˆ˜λŠ” ν•¨μˆ˜ μ •μ˜κ°€ ν‰κ°€λ˜μ–΄ ν•¨μˆ˜ 객체λ₯Ό μƒμ„±ν•˜λŠ” μ‹œμ μ— ν”„λ‘œν† νƒ€μž…λ„ λ”λΆˆμ–΄ μƒμ„±λœλ‹€.

console.log(Person.prototype); // {constructor: ƒ}

function Person(name){ 
// ν•¨μˆ˜ μ„ μ–Έλ¬ΈμœΌλ‘œ μ •μ˜λ˜μ—ˆκΈ° λ•Œλ¬Έμ— ν˜Έμ΄μŠ€νŒ…λ˜μ–΄ μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진에 μ˜ν•΄
// ν‰κ°€λ‹¨κ³„μ—μ„œ ν•¨μˆ˜μ΄λ¦„κ³Ό λ™μΌν•œ μ‹λ³„μžκ°€ μ•”λ¬΅μ μœΌλ‘œ μƒμ„±λ˜κ³  Person ν•¨μˆ˜ 객체가 ν• λ‹Ήλ˜μ–΄ 있음
// μ΄λ•Œ μƒμ„±μž ν•¨μˆ˜μ˜ prototype ν”„λ‘œνΌν‹°λ„ λ”λΆˆμ–΄ μƒμ„±λ˜κ³ , μƒμ„±λœ ν”„λ‘œν† νƒ€μž…μ€ Person μƒμ„±μž ν•¨μˆ˜μ˜
// prototype ν”„λ‘œνΌν‹°μ— λ°”μΈλ”©λœλ‹€.
    this.name = name;
}

μœ„ μ½”λ“œ 처럼 μƒμ„±λœ ν”„λ‘œν† νƒ€μž…μ€ 였직 constructor ν”„λ‘œνΌν‹°λ§Œ 가지고, ν”„λ‘œν† νƒ€μž…λ„ 객체이기 λ•Œλ¬Έμ— ν”„λ‘œν† νƒ€μž… μžμ‹ μ˜ ν”„λ‘œν† νƒ€μž…μ„ 가진닀. μƒμ„±λœ ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œν† νƒ€μž…μ€ Object.prototype이 κ°€λ¦¬ν‚€λŠ” 객체닀. 이처럼 μ‚¬μš©μž μ •μ˜ μƒμ„±μž ν•¨μˆ˜λŠ” μžμ‹ μ΄ ν‰κ°€λ˜μ–΄ ν•¨μˆ˜ 객체둜 μƒμ„±λ˜λŠ” μ‹œμ μ— ν”„λ‘œν† νƒ€μž…λ„ λ”λΆˆμ–΄ μƒμ„±λ˜λ©°, μƒμ„±λœ ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œν† νƒ€μž…μ€ μ–Έμ œλ‚˜ Object.prototype이닀.

 

19.5.2 빌트인 μƒμ„±μž ν•¨μˆ˜μ™€ ν”„λ‘œν† νƒ•μž… 생성 μ‹œμ 

  빌트인 μƒμ„±μž ν•¨μˆ˜λ„ 일반 ν•¨μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ 빌트인 μƒμ„±μž ν•¨μˆ˜κ°€ μƒμ„±λ˜λŠ” μ‹œμ μ— ν”„λ‘œν† νƒ€μž…μ΄ μƒμ„±λœλ‹€. λͺ¨λ“  빌트인 μƒμ„±μž ν•¨μˆ˜λŠ” μ „μ—­ 객체(window,global)κ°€ μƒμ„±λ˜λŠ” μ‹œμ μ— μƒμ„±λœλ‹€. μƒμ„±λœ ν”„λ‘œν† νƒ€μž…μ€ 빌트인 μƒμ„±μž ν•¨μˆ˜μ˜ prototype ν”„λ‘œνΌν‹°μ— λ°”μΈλ”©λœλ‹€.

결둠적으둜 ν”„λ‘œν† νƒ€μž…μ€ 객체가 μƒμ„±λ˜κΈ° 이전에 이미 κ°μ²΄ν™”λ˜μ–΄ μ‘΄μž¬ν•œλ‹€. 이후 μƒμ„±μž ν•¨μˆ˜ λ˜λŠ” λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²•μœΌλ‘œ 객체λ₯Ό μƒμ„±ν•˜λ©΄ ν”„λ‘œν† νƒ€μž…μ€ μƒμ„±λœ 객체의 [[Prototype]] λ‚΄λΆ€ μŠ¬λ‘―μ— ν• λ‹Ήλœλ‹€. 이둜써 μƒμ„±λœ κ°μ²΄λŠ” ν”„λ‘œν† νƒ€μž…μ„ μƒμ†λ°›λŠ”λ‹€.

 

19.6 객체 생성 방식과 ν”„λ‘œν† νƒ€μž…μ˜ κ²°μ •

19.6.1 객체 λ¦¬ν„°λŸ΄μ— μ˜ν•΄ μƒμ„±λœ 객체의 ν”„λ‘œν† νƒ€μž…

  객체 λ¦¬ν„°λŸ΄μ— μ˜ν•΄ μƒμ„±λ˜λŠ” 객체의 ν”„λ‘œν† νƒ€μž…μ€ Object.prototype이닀. κ·ΈλŸ¬λ―€λ‘œ, Object.prototype이 κ°€λ¦¬ν‚€λŠ” 객체가 가지고 μžˆλŠ” ν”„λ‘œν† νƒ€μž…κ³Ό λ©”μ„œλ“œλ₯Ό 객체 λ¦¬ν„°λŸ΄μ— μ˜ν•΄ μƒμ„±λ˜λŠ” κ°μ²΄λŠ” λͺ¨λ‘ μ‚¬μš©ν•  수 μžˆλ‹€.

const child = { x: 1 };

console.log(child.constructor); // ƒ Object() { [native code] }
console.log(child.hasOwnProperty('x')); // true 
// hasOwnPropertyλ©”μ„œλ“œλŠ” Object.prototype이 κ°€λ¦¬ν‚€λŠ” 객체의 λ©”μ„œλ“œλ‹€. 
// 즉, child객체의 ν”„λ‘œν† νƒ€μž…μ˜ λ©”μ„œλ“œλ‹€.

19.6.2 Object μƒμ„±μž ν•¨μˆ˜μ— μ˜ν•΄ μƒμ„±λœ 객체의 ν”„λ‘œν† νƒ€μž…

  객체 λ¦¬ν„°λŸ΄μ— μ˜ν•΄ μƒμ„±λœ 객체와 λ™μΌν•œ ꡬ쑰λ₯Ό κ°–λŠ”λ‹€. 즉, Object.prototype이 κ°€λ¦¬ν‚€λŠ” 객체가 Object μƒμ„±μž ν•¨μˆ˜λ₯Ό 톡해 λ§Œλ“  객체의 ν”„λ‘œν† νƒ€μž…μ΄λ‹€.

 

19.6.3 μƒμ„±μž ν•¨μˆ˜μ— μ˜ν•΄ μƒμ„±λœ 객체의 ν”„λ‘œν† νƒ€μž…

  μƒμ„±μž ν•¨μˆ˜μ— μ˜ν•΄ μƒμ„±λœ 객체의 ν”„λ‘œν† νƒ€μž…μ€ ν•΄λ‹Ή 객체λ₯Ό λ§Œλ“€μ–΄ λ‚Έ μƒμ„±μž ν•¨μˆ˜μ˜ prototype ν”„λ‘œνΌν‹°μ— λ°”μΈλ”©λ˜μ–΄ μžˆλŠ” 객체닀.

function Person(name){
    this.name = name;
}

const person1 = new Person('woo');
console.log(person1.constructor);
/*
ƒ Person(name){
    this.name = name;
}
*/
console.log(person1.__proto__); // constructor: ƒ Person(name)
console.log(Person.prototype); // constructor: ƒ Person(name)

μ£Όμ˜ν•΄μ•Ό ν•  점은 ν‘œμ€€ 빌트인 객체인 Object μƒμ„±μž ν•¨μˆ˜μ™€ λ”λΆˆμ–΄ μƒμ„±λœ ν”„λ‘œν† νƒ€μž… Object.prototype은 λ‹€μ–‘ν•œ 빌트인 λ©”μ„œλ“œλ₯Ό 가지고 μžˆμ§€λ§Œ, μ‚¬μš©μž μ •μ˜ μƒμ„±μž ν•¨μˆ˜ Personκ³Ό λ”λΆˆμ–΄ μƒμ„±λœ ν”„λ‘œν† νƒ€μž… Person.prototype의 ν”„λ‘œνΌν‹°λŠ” constructor뿐이닀.

 

19.7 ν”„λ‘œν† νƒ€μž… 체인

  μœ„μ—μ„œ μ–ΈκΈ‰ν–ˆλ“―μ΄, κ°μ²΄λŠ” ν•˜λ‚˜μ˜ ν”„λ‘œν† νƒ€μž…μ„ κ°€μ§€λŠ”λ° 객체의 ν”„λ‘œν† νƒ€μž…λ„ κ°μ²΄μ΄λ―€λ‘œ ν”„λ‘œν† νƒ€μž…λ„ μžμ‹ μ˜ ν”„λ‘œν† νƒ€μž…μ„ κ°–λŠ”λ‹€. ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œν† νƒ€μž…μ€ μ–Έμ œλ‚˜ Object.prototype이닀. μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 객체의 ν”„λ‘œνΌν‹°μ— μ ‘κ·Όν•˜λ €κ³  ν•  λ•Œ ν•΄λ‹Ή 객체에 μ ‘κ·Όν•˜λ €λŠ” ν”„λ‘œνΌν‹°κ°€ μ—†λ‹€λ©΄ [[Prototype]] λ‚΄λΆ€ 슬둯의 μ°Έμ‘°λ₯Ό 따라 μžμ‹ μ˜ λΆ€λͺ¨ 역할을 ν•˜λŠ” ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œνΌν‹°λ₯Ό 순차적으둜 κ²€μƒ‰ν•œλ‹€. 이λ₯Ό ν”„λ‘œν† νƒ€μž… 체인이라 ν•œλ‹€. κ·ΈλŸ¬λ―€λ‘œ λͺ¨λ“  객체의 ν”„λ‘œν† νƒ€μž… 쒅점은 Object.prototype이고 Object.prototype의 객체가 가지고 μžˆλŠ” ν”„λ‘œνΌν‹°μ™€ λ©”μ„œλ“œλ“€μ„ λͺ¨λ“  객체가 μ΄μš©ν•  수 μžˆλŠ” 것이닀.(__proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹° λ“±) 참고둜 Object.prototype의 ν”„λ‘œν† νƒ€μž…, 즉 [[Prototype]] λ‚΄λΆ€ 슬둯의 값은 null이닀. ν”„λ‘œν† νƒ€μž… 체인의 쒅점인 Object.prototypeμ—μ„œλ„ ν”„λ‘œνΌν‹°λ₯Ό 검색할 수 μ—†λŠ” 경우 undefinedλ₯Ό λ°˜ν™˜ν•œλ‹€. μ΄λ•Œ μ—λŸ¬λŠ” λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€.

 

19.9 ν”„λ‘œν† νƒ€μž…μ˜ ꡐ체

  ν”„λ‘œν† νƒ€μž…μ€ μž„μ˜μ˜ λ‹€λ₯Έ 객체둜 λ³€κ²½ν•  수 μžˆλ‹€. 이것은 λΆ€λͺ¨ 객체인 ν”„λ‘œν† νƒ€μž…μ„ λ™μ μœΌλ‘œ λ³€κ²½ν•  수 μžˆλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€.

 

19.9.1 μƒμ„±μž ν•¨μˆ˜μ— μ˜ν•œ ν”„λ‘œν† νƒ€μž…μ˜ ꡐ체

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


Person.prototype = {
    sayHello(){
        console.log(`hi my name is ${this.name}`);
    }
};

return Person;
}());

const me = new Person('lee');

me.sayHello(); // hi my name is lee
console.log(me.constructor); // ƒ Object() { [native code] }

  μœ„μ˜ μ½”λ“œλ₯Ό 보면 Person.prototype에 객체 λ¦¬ν„°λŸ΄μ„ ν• λ‹Ήν–ˆλ‹€. μ΄λŠ” Person μƒμ„±μž ν•¨μˆ˜κ°€ 생성할 객체의 ν”„λ‘œν† νƒ€μž…μ„ 객체 λ¦¬ν„°λŸ΄λ‘œ κ΅μ²΄ν•œ 것이닀. ν”„λ‘œν† νƒ€μž…μœΌλ‘œ κ΅μ²΄ν•œ 객체 λ¦¬ν„°λŸ΄μ—λŠ” constructor ν”„λ‘œνΌν‹°κ°€ μ—†λ‹€. constructor ν”„λ‘œνΌν‹°λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진이 ν”„λ‘œν† νƒ€μž…μ„ 생성할 λ•Œ μ•”λ¬΅μ μœΌλ‘œ μΆ”κ°€ν•œ ν”„λ‘œνΌν‹°λ‹€. λ”°λΌμ„œ me 객체의 μƒμ„±μž ν•¨μˆ˜λ₯Ό κ²€μƒ‰ν•˜λ©΄ Person이 μ•„λ‹ˆλΌ ν”„λ‘œν† νƒ€μž… 체인에 μ˜ν•΄μ„œ Objectκ°€ λ‚˜μ˜¨λ‹€.

 

19.9.2 μΈμŠ€ν„΄μŠ€μ— μ˜ν•œ ν”„λ‘œν† νƒ€μž…μ˜ ꡐ체

  ν”„λ‘œν† νƒ€μž…μ€ μƒμ„±μž ν•¨μˆ˜μ˜ prototype ν”„λ‘œνΌν‹°λΏλ§Œ μ•„λ‹ˆλΌ μΈμŠ€ν„΄μŠ€μ˜ Object.prototypeμœΌλ‘œλΆ€ν„° 상속받은__proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 μ ‘κ·Όν•  수 μžˆλ‹€. λ”°λΌμ„œ μΈμŠ€ν„΄μŠ€μ˜ __proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 ν”„λ‘œν† νƒ€μž…μ„ ꡐ체할 수 μžˆλ‹€. μƒμ„±μž ν•¨μˆ˜μ˜ prototype ν”„λ‘œνΌν‹°μ— λ‹€λ₯Έ μž„μ˜μ˜ 객체λ₯Ό λ°”μΈλ”©ν•˜λŠ” 것은 λ―Έλž˜μ— 생성할 μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž…μ„ κ΅μ²΄ν•˜λŠ” 것이닀. __proto__μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 ν”„λ‘œν† νƒ€μž…μ„ κ΅μ²΄ν•˜λŠ” 것은 이미 μƒμ„±λœ 객체의 ν”„λ‘œν† νƒ€μž…μ„ κ΅μ²΄ν•˜λŠ” 것이닀. μƒμ„±μž ν•¨μˆ˜μ— μ˜ν•œ ν”„λ‘œν† νƒ€μž… ꡐ체와 μΈμŠ€ν„΄μŠ€μ— μ˜ν•œ ν”„λ‘œν† νƒ€μž… κ΅μ²΄λŠ” 별닀λ₯Έ 차이가 μ—†μ–΄ λ³΄μ΄μ§€λ§Œ, λ―Έλ¬˜ν•œ 차이가 μ‘΄μž¬ν•œλ‹€.

 

β—Ž μƒμ„±μž ν•¨μˆ˜μ˜ prototype ν”„λ‘œνΌν‹°λ₯Ό 톡해 κ΅μ²΄ν•˜λŠ” 경우 μƒμ„±μž ν•¨μˆ˜μ˜ prototype은 ꡐ체된 ν”„λ‘œν† νƒ€μž… 객체λ₯Ό 가리킨닀.

β—Ž μΈμŠ€ν„΄μŠ€μ˜ __proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 κ΅μ²΄ν•˜λŠ” 경우 μƒμ„±μž ν•¨μˆ˜μ˜ prototype은 ꡐ체된 ν”„λ‘œν† νƒ€μž… 객체λ₯Ό 가리킀지 μ•ŠλŠ”λ‹€.

β—Ž ꡐ체된 ν”„λ‘œν† νƒ€μž… κ°μ²΄λŠ” constructor ν”„λ‘œνΌν‹°λ₯Ό 갖지 μ•ŠλŠ”λ‹€. (직접 μΆ”κ°€ν•΄μ„œ μ—°κ²°ν•  μˆ˜λŠ” 있음)

 

19.10 instanceof μ—°μ‚°μž

  instanceof μ—°μ‚°μžλŠ” 이항 μ—°μ‚°μžλ‘œ μ’Œλ³€μ— 객체λ₯Ό κ°€λ¦¬ν‚€λŠ” μ‹λ³„μž, μš°λ³€μ— μƒμ„±μž ν•¨μˆ˜λ₯Ό κ°€λ¦¬ν‚€λŠ” μ‹λ³„μžλ₯Ό ν”Όμ—°μ‚°μžλ‘œ λ°›λŠ”λ‹€. λ§Œμ•½ μš°λ³€μ˜ ν”Όμ—°μ‚°μžκ°€ ν•¨μˆ˜κ°€ μ•„λ‹Œ 경우 TypeErrorκ°€ λ°œμƒν•œλ‹€. μš°λ³€μ˜ μƒμ„±μž ν•¨μˆ˜μ˜ prototype에 λ°”μΈλ”©λœ 객체가 μ’Œλ³€μ˜ 객체의 ν”„λ‘œν† νƒ€μž… 체인 상에 μ‘΄μž¬ν•˜λ©΄ true둜 ν‰κ°€λ˜κ³ , 그렇지 μ•Šμ€ κ²½μš°μ—λŠ” false둜 ν‰κ°€λœλ‹€.

//instace of μ—°μ‚°μž
function Person(name){
    this.name = name;
}

const me = new Person('lee');

console.log(me instanceof Person); // true
console.log(me instanceof Object); // ture

 

μ€‘μš”ν•œ 점은 instanceof μ—°μ‚°μžλŠ” ν”„λ‘œν† νƒ€μž…μ˜ constructor ν”„λ‘œνΌν‹°κ°€ κ°€μ‹œν‚€λŠ” μƒμ„±μž ν•¨μˆ˜λ₯Ό μ°ΎλŠ” 것이 μ•„λ‹ˆλΌ μƒμ„±μž ν•¨μˆ˜μ˜ prototype에 λ°”μΈλ”©λœ 객체가 ν”„λ‘œν† νƒ€μž… 체인 상에 μ‘΄μž¬ν•˜λŠ”μ§€ ν™•μΈν•œλ‹€λŠ” 것이닀.

 

19.12 정적 ν”„λ‘œνΌν‹°/λ©”μ„œλ“œ

  정적 ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλŠ” μƒμ„±μž ν•¨μˆ˜λ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€ μ•Šμ•„λ„ μ°Έμ‘°/ν˜ΈμΆœν•  수 μžˆλŠ” ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλ₯Ό λ§ν•œλ‹€.

//정적 ν”„λ‘œνΌν‹°/λ©”μ„œλ“œ

function Person(name){
    this.name = name;
}

Person.prototype.sayHello = function(){
    console.log(`hi ${this.name}`);
};

//정적 ν”„λ‘œνΌν‹° 생성
Person.staticprop = 'static prop';
//정적 λ©”μ„œλ“œ 생성
Person.staticMethod = function(){
    console.log('staticMethod');
};

const person1 = new Person('lee');


person1.sayHello(); // hi lee

console.log(Person.staticprop); // static prop
Person.staticMethod(); // staticMethod


console.log(person1.staticprop); // person1의 ν”„λ‘œν† νƒ€μž… μ²΄μΈμ—λŠ” μ—†λŠ” ν”„λ‘œνΌν‹° μ΄λ―€λ‘œ undefined λ°˜ν™˜
// person1.staticMethod(); // TypeError λ°œμƒ

Person μƒμ„±μž ν•¨μˆ˜λŠ” κ°μ²΄μ΄λ―€λ‘œ μžμ‹ μ˜ μ˜¨μ „ν•œ ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•  수 μžˆλ‹€. Person μƒμ„±μž ν•¨μˆ˜ 객체가 μ†Œμœ ν•œ ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλ₯Ό 정적 ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλΌ ν•œλ‹€. 정적 ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλŠ” μƒμ„±μž ν•¨μˆ˜κ°€ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€λ‘œ μ°Έμ‘°/ν˜ΈμΆœν•  수 μ—†λ‹€. μ™œλƒν•˜λ©΄ μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž… 체인에 λ“€μ–΄μžˆλŠ” ν”„λ‘œνΌν‹°/λ©”μ„œλ“œκ°€ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ΄λ‹€. μ‰½κ²Œ 말해 μƒμ„±μž ν•¨μˆ˜λ„ κ°μ²΄μ΄λ―€λ‘œ 자기 μžμ‹ μ˜ ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•  수 있고, μƒμ„±μž ν•¨μˆ˜ μžμ‹ μ΄ μ†Œμœ ν•œ ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλ₯Ό 정적 ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλΌκ³  λͺ…λͺ…ν•œ 것이닀. 

 

예λ₯Ό λ“€μ–΄, Object.getOwnPropertyDescriptor λ©”μ„œλ“œλŠ” Object 빌트인 μƒμ„±μž ν•¨μˆ˜μ˜ 정적 λ©”μ„œλ“œλ‹€. λ°˜λŒ€λ‘œObject.prototype.hasOwnPropertyλ‚˜ Object.prototype.__proto__λ©”μ„œλ“œλŠ” ν”„λ‘œν† νƒ€μž… 객체의 λ©”μ„œλ“œλ‹€.

λ”°λΌμ„œ ν‘œκΈ°λ²•λ§ŒμœΌλ‘œλ„ 정적 ν”„λ‘œνΌν‹°/λ©”μ„œλ“œμ™€ ν”„λ‘œν† νƒ€μž… ν”„λ‘œνΌν‹°/λ©”μ„œλ“œλ₯Ό ꡬ별할 수 μžˆλ‹€.

 

19.13 ν”„λ‘œνΌν‹° 쑴재 확인

19.13.1 inμ—°μ‚°μž

  in μ—°μ‚°μžλŠ” 객체 내에 νŠΉμ • ν”„λ‘œνΌν‹°κ°€ μ‘΄μž¬ν•˜λŠ”μ§€ μ—¬λΆ€λ₯Ό ν™•μΈν•œλ‹€. μ£Όμ˜ν•΄μ•Ό ν•  점은 in μ—°μ‚°μžλŠ” 확인 λŒ€μƒ 객체의 ν”„λ‘œνΌν‹°λΏλ§Œ μ•„λ‹ˆλΌ 확인 λŒ€μƒ 객체가 상속받은 λͺ¨λ“  ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œνΌν‹°λ₯Ό ν™•μΈν•˜μ—¬ λΆˆλ¦¬μ–Έκ°’μœΌλ‘œ λ°˜ν™˜ν•œλ‹€.

// in μ—°μ‚°μžλ‘œ ν”„λ‘œνΌν‹° 쑴재 확인
const person = {
    name : 'lee',
    address : 'seoul'
};

console.log('name' in person); // true
console.log('address' in person); // true
console.log('age' in person); // false 
console.log('__proto__' in person); // true (ν”„λ‘œν† μ²΄μΈ λ‚΄μ˜ λͺ¨λ“  ν”„λ‘œνΌν‹°λ₯Ό 검색함)

19.13.2 Object.prototype.hasOwnProperty λ©”μ„œλ“œ(ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œλ‹€.)

  Object.prototype.hasOwnProperty λ©”μ„œλ“œλŠ”  인수둜 전달받은 ν”„λ‘œνΌν‹° ν‚€κ°€ 객체 고유의 ν”„λ‘œνΌν‹° 킀인 κ²½μš°μ—λ§Œ trueλ₯Ό λ°˜ν™˜ν•œλ‹€. 즉, 상속받은 ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œνΌν‹° 킀인 경우 falseλ₯Ό λ°˜ν™˜ν•œλ‹€.

const person = {
    name : 'lee',
    address : 'seoul'
};

console.log(person.hasOwnProperty('name')); // true
console.log(person.hasOwnProperty('address')); // true
console.log(person.hasOwnProperty('age')); // false
console.log(person.hasOwnProperty('__proto__')); // false (ν•΄λ‹Ή 객체 고유의 ν”„λ‘œνΌν‹°λ§Œ 검색함)

19.14 ν”„λ‘œνΌν‹° μ—΄κ±°

19.14.1 for...in λ¬Έ

  객체의 λͺ¨λ“  ν”„λ‘œνΌν‹°λ₯Ό μˆœνšŒν•˜λ©° μ—΄κ±°ν•˜λ €λ©΄ for...in 문을 μ‚¬μš©ν•œλ‹€. for...in 문은 객체의 ν”„λ‘œνΌν‹° 개수만큼 μˆœνšŒν•˜λ©° for...in 문의 λ³€μˆ˜ μ„ μ–Έλ¬Έμ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜μ— ν”„λ‘œνΌν‹° ν‚€λ₯Ό ν• λ‹Ήν•œλ‹€. μ£Όμ˜ν•΄μ•Ό ν•  점은 for...in 문은 in μ—°μ‚°μžμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ 순회 λŒ€μƒ 객체의 ν”„λ‘œνΌν‹°λΏλ§Œ μ•„λ‹ˆλΌ 상속받은 ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œνΌν‹°κΉŒμ§€ μ—΄κ±°ν•œλ‹€.(μ •ν™•ν•˜κ²Œ λ§ν•˜μžλ©΄ ν”„λ‘œν† νƒ€μž… 체인 λ‚΄μ˜ ν”„λ‘œνΌν‹° 쀑 [[Enumerable]]의 값이 true인 ν”„λ‘œνΌν‹°λ“€λ§Œ μ—΄κ±°ν•œλ‹€.)κ·Έλ ‡κΈ° λ•Œλ¬Έμ— ν•΄λ‹Ή 객체의 κ³ μœ ν•œ ν”„λ‘œνΌν‹°λ§Œ μˆœνšŒν•˜κ³ μž ν•œλ‹€λ©΄, Object.prototype.hasOwnPropertyλ©”μ„œλ“œλ₯Ό ν™œμš©ν•˜μ—¬ 쑰건문으둜 κ³ μœ ν•œ ν”„λ‘œνΌν‹°λ§Œ 골라내야 ν•œλ‹€.

// for .. in 문으둜 λͺ¨λ“  ν”„λ‘œνΌν‹° μˆœνšŒν•˜κΈ°
//    for(λ³€μˆ˜ μ„ μ–Έ in 객체){}

const man = {
    name : 'lee',
    address : 'seoul'
};

for(const key in man){
    console.log(key + ':' + man[key]);
}

/* 
name:lee
address:seoul
상속받은 ν”„λ‘œνΌν‹°λ“€λ„ μˆœνšŒν•˜μ§€λ§Œ ν”„λ‘œνΌν‹° μ–΄νŠΈλ¦¬λ·°νŠΈμ˜ Enumerable이 false인 κ²½μš°μ—λŠ” μˆœνšŒλ˜μ§€ μ•ŠλŠ”λ‹€.
*/


//boy객체의 κ³ μœ ν•œ ν”„λ‘œνΌν‹°λ“€λ§Œ μˆœνšŒν•˜κΈ°
const boy = {
    name : 'lee',
    address : 'seoul',
    __proto__ : {age : 20} // μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό μ΄μš©ν•΄μ„œ 직접 상속
};

for(const key in boy){
    if(!boy.hasOwnProperty(key)){
        continue;
    }
    console.log(key + ':' + boy[key]);
}

/*
name:lee
address:seoul
*/

19.14.2 Object.keys/Object.values/Object.entries λ©”μ„œλ“œ(Object μƒμ„±μž ν•¨μˆ˜μ˜ 정적 λ©”μ„œλ“œλ‹€.)

  for...in 문을 ν™œμš©ν•œ 객체 μžμ‹ μ˜ κ³ μœ ν•œ ν”„λ‘œνΌν‹°λ§Œ μˆœνšŒν•˜κΈ° μœ„ν•œ 방법은 κ½€ 번거둜운 방법이닀. κ·Έλž˜μ„œ 객체 μžμ‹ μ˜ κ³ μœ ν•œ ν”„λ‘œνΌν‹°λ§Œ μ—΄κ±°ν•˜κΈ° μœ„ν•΄μ„œλŠ” for...in 문을 μ‚¬μš©ν•˜λŠ” 것보닀Object.keys/Object.values/Object.entries λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€. Object.keys 정적 λ©”μ„œλ“œλŠ” 객체 μžμ‹ μ˜ μ—΄κ±° κ°€λŠ₯ν•œ 고유의 ν”„λ‘œνΌν‹° ν‚€λ₯Ό λ°°μ—΄λ‘œ λ°˜ν™˜ν•œλ‹€. 

const girl = {
    name : 'lee',
    address : 'seoul',
    __proto__ : {age : 20}
}; 

console.log(Object.keys(girl)); 
// ['name', 'address'] 객체 μžμ‹ μ˜ μ—΄κ±°κ°€λŠ₯ν•œ 고유의 ν”„λ‘œνΌν‹° ν‚€λ₯Ό μ—΄κ±°

Object.values 정적 λ©”μ„œλ“œλŠ” 객체 μžμ‹ μ˜ μ—΄κ±° κ°€λŠ₯ν•œ 고유 ν”„λ‘œνΌν‹° 값을 λ°°μ—΄λ‘œ λ°˜ν™˜ν•œλ‹€.

const girl = {
    name : 'lee',
    address : 'seoul',
    __proto__ : {age : 20}
};

console.log(Object.values(girl)); 
// ['lee', 'seoul'] 객체 μžμ‹ μ˜ μ—΄κ±° κ°€λŠ₯ν•œ 고유의 ν”„λ‘œνΌν‹° κ°’λ₯Ό μ—΄κ±°

Object.entries 정적 λ©”μ„œλ“œλŠ” 객체 μžμ‹ μ˜ μ—΄κ±° κ°€λŠ₯ν•œ 고유 ν”„λ‘œνΌν‹° 킀와 κ°’μ˜ 쌍의 배열을 배열에 λ‹΄μ•„ λ°˜ν™˜ν•œλ‹€.

const girl = {
    name : 'lee',
    address : 'seoul',
    __proto__ : {age : 20}
};

console.log(Object.entries(girl)); 
// [['name', 'lee'],['address', 'seoul']] 
//객체 μžμ‹ μ˜ μ—΄κ±°κ°€λŠ₯ν•œ 고유의 ν”„λ‘œνΌν‹° 킀와 κ°’μ˜ 쌍의 배열을 배열에 λ‹΄μ•„ λ°˜ν™˜