[Javascript] ν”„λ‘œν† νƒ€μž…(2) ν”„λ‘œν† νƒ€μž… 객체

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

λΈŒλΌμš°μ € μ½˜μ†”μ°½μ— 객체λ₯Ό μƒμ„±ν•˜κ³  찍어보면 λ‚΄κ°€ μž…λ ₯ν•œ ν”„λ‘œνΌν‹° 외에도 [[Prototype]]: ObjectλΌλŠ” ν•­λͺ©μ΄ 같이 λœ¬λ‹€.

μ΄λ•Œ μ–˜λ₯Ό 펼쳐보면 λ­”κ°€ μž”λœ© λ‚˜μ˜€λŠ”λ°, 이게 ν”„λ‘œν† νƒ€μž…μ΄λ‹€.

ν”„λ‘œν† νƒ€μž… 직접 μ‚΄νŽ΄λ³΄κΈ°

 

 

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

μ—¬κΈ°μ„œ [[Prototype]]에 μžˆλŠ” ν”„λ‘œν† νƒ€μž…μ— μ ‘κ·Όν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ˜λŠ” 것이 __proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°μ΄λ‹€.

μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” 자체적인 값을 가지고 μžˆλŠ”κ²Œ μ•„λ‹ˆλΌ, get / set와 같은 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ μ‚¬μš©λœλ‹€.

const obj = {}
const parent = {x: 1}

obj.__proto__   // μ—¬κΈ°μ„œλŠ” get __object__λ₯Ό ν˜ΈμΆœν•˜κ³ 
obj.__proto__ = parent   // μ—¬κΈ°μ„œλŠ” set __object__λ₯Ό ν˜ΈμΆœν•¨

console.log(obj.x)  // 1

 

__proto__ λŠ” 상속을 톡해 μ‚¬μš©λ¨

__proto__ λŠ” 객체가 직접 μ†Œμœ ν•˜λŠ” ν”„λ‘œνΌν‹°κ°€ μ•„λ‹ˆλΌ, Object.prototype의 ν”„λ‘œνΌν‹°μ΄λ‹€.

κ·Έλ ‡κΈ°λ•Œλ¬Έμ— 상속을 톡해 Object.prototype.__proto__λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

const obj = {};

// objλŠ” 직접 __proto__ ν”„λ‘œνΌν‹°λ₯Ό 가지고 μžˆμ§€ μ•ŠμŒ
console.log(obj.hasOwnProperty('__proto__')); // false

// ν•˜μ§€λ§Œ __proto__λ₯Ό μ‚¬μš©ν•  수 있음
console.log(obj.__proto__ === Object.prototype); // true

// __proto__λŠ” μ‹€μ œλ‘œ Object.prototype의 ν”„λ‘œνΌν‹°μž„
console.log(Object.prototype.hasOwnProperty('__proto__')); // true


// 즉, 이런 ν˜•νƒœλ₯Ό κ°€μ§€λŠ” κ±°μž„
obj ---> obj.__proto__ ---> Object.prototype
// obj μžμ²΄λŠ” λΉ„μ–΄μžˆμŒ {}
// objλŠ” Object.prototype을 μƒμ†λ°›μŒ
// Object.prototype에 __proto__ getter/setterκ°€ μ •μ˜λ˜μ–΄ 있음

μ’€ 더 정리λ₯Ό ν•˜μžλ©΄

  1. λͺ¨λ“  κ°μ²΄λŠ” Object.prototype을 μƒμ†λ°›μŒ
  2. __proto__λŠ” Object.prototype에 μ •μ˜λœ νŠΉλ³„ν•œ μ ‘κ·Όμž ν”„λ‘œνΌν‹°
  3. λͺ¨λ“  κ°μ²΄λŠ” 이 __proto__λ₯Ό 상속받아 μ‚¬μš©
  4. 이런 λ°©μ‹μœΌλ‘œ ν”„λ‘œν† νƒ€μž… 체인 μ‘°μž‘μ΄ κ°€λŠ₯

μ™œ μ΄λ ‡κ²Œ λΆˆνŽΈν•˜κ²Œ μ“°λŠ”μ§€? = ν”„λ‘œν† νƒ€μž… 체인이 μƒμ„±λ˜λŠ” 것을 λ°©μ§€ν•˜λ €κ΅¬

const parent = {}
const child = {}

child.__proto__ = parent
parent.__proto__ = child  // TypeError: Cyclic __proto__ value

μœ„μ˜ μ˜ˆμ‹œμ²˜λŸΌ μ„œλ‘œμ˜ ν”„λ‘œν† νƒ€μž…μ„ μ„€μ •ν•˜λ©΄ νƒ€μž…μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.
이런 ν˜„μƒμ„ λ°©μ§€ν•˜κΈ° μœ„ν•΄μ„œ ν”„λ‘œν† νƒ€μž… 체인은 단방ν–₯ λ§ν¬λ“œλ¦¬μŠ€νŠΈ ν˜•νƒœλ‘œ κ΅¬ν˜„μ΄ λ˜μ–΄μ•Ό ν•œλ‹€. μˆœν™˜ μ°Έμ‘°λ₯Ό 막기 μœ„ν•΄μ„œ __proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό ν†΅ν•΄μ„œ μ ‘κ·Όν•˜κ³  κ΅μ²΄ν•˜λ„λ‘ κ΅¬ν˜„μ΄ λ˜μ–΄μžˆλŠ” 것..

 

 

사싀은 근데, ꢌμž₯λ˜μ§€ μ•ŠμŒ

ES5κΉŒμ§€λŠ” __proto__ μ ‘κ·ΌμžλŠ” ν¬ν•¨λ˜μ§€ μ•Šμ€ λΉ„ν‘œμ€€μ΄μ—ˆλ‹€. ES6에 μ™€μ„œμ•Ό μ§€μ›ν•˜λŠ” κΈ°λŠ₯μ΄μ§€λ§Œ, ꢌμž₯λ˜μ§€λŠ” μ•ŠλŠ”λ‹€.

μ™œλƒν•˜λ©΄, λͺ¨λ“  객체가 __proto__λ₯Ό μ‚¬μš©ν•  수 μžˆλŠ”κ²Œ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ—...

const obj = Object.create(null)
console.log(obj.__proto__) // undefined

 

κ·Έλž˜μ„œ ꢌμž₯λ˜λŠ” 방법은

  • μ°Έμ‘°ν•˜κ³  싢을 λ•Œ : Object.getPrototypeOf
  • κ΅μ²΄ν•˜κ³  싢을 λ•Œ: Object.setPrototypeOf
const obj = {}
const parent = {x : 1}

Object.getPrototypeOf(obj)  // obj의 ν”„λ‘œν† νƒ€μž…μ„ κ°€μ Έμ˜΄
Object.setPrototypeOf(obj, parent)   // obj의 ν”„λ‘œν† νƒ€μž…μ„ parent둜 ꡐ체

console.log(obj.x)  // 1

 

 


πŸ“Œ ν•¨μˆ˜ 객체의 prototype ν”„λ‘œνΌν‹°

ν•¨μˆ˜λ„ κ°μ²΄μ΄λ―€λ‘œ prototype ν”„λ‘œνΌν‹°λ₯Ό 가진닀.

μ΄λ•Œ ν•¨μˆ˜ 객체가 μ†Œμœ ν•˜λŠ” prototype ν”„λ‘œνΌν‹°λŠ” μƒμ„±μž ν•¨μˆ˜κ°€ 생성할 μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž…μ„ 가리킨닀.

(function () {}).hasOwnProperty('prototype')

κ·Έλž˜μ„œ μ΄λŸ°μ‹μœΌλ‘œ λΉˆν•¨μˆ˜λ„ prototype을 가진닀.

μ™œλƒν•˜λ©΄ 이 ν•¨μˆ˜λ₯Ό λ‚˜μ€‘μ— μƒμ„±μž ν•¨μˆ˜λ‘œ μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ—

 

ν•˜μ§€λ§Œ, 일반 객체의 κ²½μš°μ—λŠ” prototype ν”„λ‘œνΌν‹°λ₯Ό 가지지 μ•ŠλŠ”λ‹€.

(객체의 경우 __proto__ λŠ” κ°€μ§€μ§€λ§Œ, prototype ν”„λ‘œνΌν‹°λŠ” 가지지 μ•ŠμŒ)

const obj = {};
console.log(obj.prototype); // undefined

 

 

그리고, ν•¨μˆ˜λŠ” μƒμ„±μž ν•¨μˆ˜λ‘œ μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ— prototype ν”„λ‘œνΌν‹°λ₯Ό κ°€μ§€λŠ”λ°,

λ§Œμ•½ μƒμ„±μž ν•¨μˆ˜λ‘œ μ‚¬μš©ν•  수 μ—†λŠ” ν•¨μˆ˜(non-constructor)인 ν™”μ‚΄ν‘œ ν•¨μˆ˜μ™€ ES6 λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„μœΌλ‘œ μ •μ˜λœ λ©”μ„œλ“œλŠ” prototype ν”„λ‘œνΌν‹°λ₯Ό 가지지 μ•ŠμŒ

// ν™”μ‚΄ν‘œ ν•¨μˆ˜
const arrowFunc = () => {};
console.log(arrowFunc.prototype); // undefined

// ES6 μΆ•μ•½ν˜•
const obj = {
  foo() {}
}
console.log(obj.foo.hasOwnProperty('prototype')  // false

 

ν•˜μ§€λ§Œ... __proto__λŠ” 가짐... (= non-constructor ν•¨μˆ˜λŠ” prototype ν”„λ‘œνΌν‹°λŠ” 가지지 μ•Šμ§€λ§Œ __proto__λŠ” 가짐)

__proto__와 prototype ν”„λ‘œνΌν‹°λŠ” μ„œλ‘œ λ™μΌν•œ ν”„λ‘œν† νƒ€μž…μ„ κ°€λ¦¬ν‚€μ§€λ§Œ ν”„λ‘œνΌν‹°λ₯Ό μ‚¬μš©ν•˜λŠ” 주체가 λ‹€λ₯΄λ‹€!

// ν™”μ‚΄ν‘œ ν•¨μˆ˜
const arrowFunc = () => {};
console.log(arrowFunc.prototype); // undefined
console.log(arrowFunc.__proto__ === Function.prototype); // true

// ES6 λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„
const obj = {
    method() {}  // λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„
};
console.log(obj.method.prototype); // undefined
console.log(obj.method.__proto__ === Function.prototype); // true

// 일반 ν•¨μˆ˜μ™€ 비ꡐ
function normalFunc() {}
console.log(normalFunc.prototype); // {constructor: ƒ}
console.log(normalFunc.__proto__ === Function.prototype); // true

 


πŸ”¨ constructor

// μƒμ„±μž ν•¨μˆ˜
function Person(name) {
  this.name = name
}

const me = new Person('Meme')

console.log(me.constructor === Person)   // true

λͺ¨λ“  ν”„λ‘œν† νƒ€μž…μ€ μžμ‹ μ„ μ°Έμ‘°ν•˜κ³  μžˆλŠ” μƒμ„±μž ν•¨μˆ˜λ₯Ό κ°€λ¦¬ν‚€λŠ” constructor ν”„λ‘œνΌν‹°λ₯Ό 가진닀. 

이 연결은 μƒμ„±μž ν•¨μˆ˜κ°€ 생성될 λ•Œ(= ν•¨μˆ˜ 객체가 생성될 λ•Œ) 이뀄진닀.

 


객체λ₯Ό μƒμ„±ν•˜λŠ” 방법 쀑, μƒμ„±μž ν•¨μˆ˜κ°€ μ•„λ‹Œ λ¦¬ν„°λŸ΄ ν‘œκΈ°λ²•μ— μ˜ν•΄ μƒμ„±λœ κ°μ²΄λŠ” ν”„λ‘œν† νƒ€μž…μ΄ μ‘΄μž¬ν• κΉŒ?

// μ΄λŸ°μ• λ“€
const obj = {}
const add = function(a, b) {return a + b}
const arr = [1, 2, 3]
const regexp = /is/ig

→ β­•, ν•˜μ§€λ§Œ μ΄λ•Œ constructor ν”„λ‘œνΌν‹°κ°€ κ°€λ¦¬ν‚€λŠ” μƒμ„±μž ν•¨μˆ˜κ°€ λ°˜λ“œμ‹œ 객체λ₯Ό μƒμ„±ν•œ μƒμ„±μž ν•¨μˆ˜λΌκ³  ν•  μˆ˜λŠ” μ—†λ‹€.

 

// Object μƒμ„±μž ν•¨μˆ˜κ°€ μ•„λ‹ˆλΌ, 객체 λ¦¬ν„°λŸ΄λ‘œ λ§Œλ“€μ—ˆμ§€λ§Œ
const obj = {}
console.log(obj.constructor === Object)   // true, Objectν•¨μˆ˜λΌκ³  λ‚˜μ˜΄


// ν•¨μˆ˜λ„ Function μƒμ„±μž ν•¨μˆ˜κ°€ μ•„λ‹ˆλΌ, ν•¨μˆ˜ μ„ μ–Έλ¬ΈμœΌλ‘œ λ§Œλ“€μ—ˆμŒ
const foo() {}
console.log(foo.constructor === Function)  // true

ν”„λ‘œν† νƒ€μž…μ€ μƒμ„±μž ν•¨μˆ˜μ™€ 같이 μƒμ„±λ˜κ³ , prototype, constructor ν”„λ‘œνΌν‹°μ— μ˜ν•΄ μ—°κ²°λ˜μ–΄ 있기 λ•Œλ¬Έμ—

즉, ν”„λ‘œν† νƒ€μž…κ³Ό μƒμ„±μž ν•¨μˆ˜λŠ” λ‹¨λ…μœΌλ‘œ μ‘΄μž¬ν•  수 μ—†κ³  늘 쌍으둜 μ‘΄μž¬ν•œλ‹€.

 

더보기
function Person(name) {
    this.name = name;
}

const person1 = new Person('Kim');

// μˆœν™˜ 관계 확인
console.log(Person.prototype.constructor === Person); // true
console.log(person1.__proto__ === Person.prototype); // true
console.log(person1.constructor === Person); // true



 

 

  • JavaScript 엔진은 ν•¨μˆ˜λ₯Ό 생성할 λ•Œ prototype 객체도 같이 생성
  • 이 prototype κ°μ²΄λŠ” μžλ™μœΌλ‘œ constructor ν”„λ‘œνΌν‹°λ₯Ό 가짐
  • constructorλŠ” λ‹€μ‹œ μ›λž˜μ˜ ν•¨μˆ˜λ₯Ό 가리킴
  • 객체가 생성될 λ•Œ μžλ™μœΌλ‘œ prototype을 __proto__둜 링크

즉,

  • λ¦¬ν„°λŸ΄λ‘œ μƒμ„±ν•˜λ“ , μƒμ„±μž ν•¨μˆ˜λ‘œ μƒμ„±ν•˜λ“ 
  • λͺ¨λ“  κ°μ²΄λŠ” λ°˜λ“œμ‹œ μ–΄λ–€ μƒμ„±μž ν•¨μˆ˜μ˜ prototypeκ³Ό 연결됨
  • 이 연결은 __proto__와 constructor ν”„λ‘œνΌν‹°λ₯Ό 톡해 μœ μ§€λ¨

 

 


그럼 ν”„λ‘œν† νƒ€μž…μ€ μ–Έμ œ 생성이 λ˜λŠ” 걸까?

=> μ•„κΉŒ ν”„λ‘œν† νƒ€μž…κ³Ό μƒμ„±μž ν•¨μˆ˜λŠ” 쌍으둜 μ‘΄μž¬ν•΄μ•Ό ν•œλ‹€ ν–ˆμœΌλ―€λ‘œ, μƒμ„±μž ν•¨μˆ˜κ°€ μƒμ„±λ˜λŠ” μ‹œμ μ— ν”„λ‘œν† νƒ€μž…λ„ μƒμ„±λœλ‹€.

  • μ‚¬μš©μž μ •μ˜ μƒμ„±μž ν•¨μˆ˜: μƒμ„±μž ν•¨μˆ˜λ‘œμ„œ ν˜ΈμΆœν•  수 μžˆλŠ” ν•¨μˆ˜(constructor) 객체가 μƒμ„±λ˜λŠ” μ‹œμ μ— ν”„λ‘œν† νƒ€μž…λ„ 생성됨
// ν•¨μˆ˜ μ •μ˜κ°€ ν‰κ°€λ˜μ–΄ ν•¨μˆ˜ 객체λ₯Ό μƒμ„±ν•˜λŠ” μ‹œμ μ— ν”„λ‘œν† νƒ€μž…λ„ 생성
console.log(Person.prototype) // {constructor: f}

// μƒμ„±μž ν•¨μˆ˜
function Person(name) {
	this.name = name
}
  • 빌트인 μƒμ„±μž ν•¨μˆ˜(Object, String, Number, Function, Array, RegExp, Date, Promise): 빌트인 μƒμ„±μž ν•¨μˆ˜κ°€ μƒμ„±λ˜λŠ” μ‹œμ μ— 생성됨 = μ „μ—­ 객체가 μƒμ„±λ˜λŠ” μ‹œμ μ— 생성
// μ „μ—­ 객체(Global Object)의 ν”„λ‘œνΌν‹°λ‘œ μ‘΄μž¬ν•˜λŠ” 빌트인 μƒμ„±μž ν•¨μˆ˜λ“€
console.log(window.Object === Object);  // true (λΈŒλΌμš°μ € ν™˜κ²½)
console.log(window.Array === Array);    // true
console.log(window.Function === Function);  // true

const obj = new Object()
console.log(obj.__proto__ === Object.prototype); // true

 

 

더보기

좔상연산 OrdinaryObjectCreate

=  JavaScriptμ—μ„œ μƒˆλ‘œμš΄ 객체λ₯Ό λ§Œλ“€κ³  ν”„λ‘œν† νƒ€μž…μ„ μ—°κ²°ν•˜λŠ” λ‚΄λΆ€ λ©”μ»€λ‹ˆμ¦˜

 

  • 객체 λ¦¬ν„°λŸ΄λ‘œ 객체λ₯Ό 생성할 λ•Œ
  • Object μƒμ„±μž ν•¨μˆ˜λ‘œ 객체λ₯Ό 생성할 λ•Œ
  • μƒμ„±μž ν•¨μˆ˜λ‘œ 생성할 λ•Œ
  • Object.create() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  λ•Œ

λ“±λ“±μ˜ μƒν™©μ—μ„œ μ“°μž„