본문 바로가기
개발/javascript

19장 프로토타입 - __proto__와 prototype

by 올럭Dev 2023. 12. 5.
728x90

__proto__prototype에 대해 알아 보겠습니다.

목차 📑

  • __proto__ 소개
  • prototype 소개

__proto__ 소개

__proto__

  • 모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입에 간접적으로 접근할 수 있습니다. __proto__는 접근자 프로퍼티 입니다.
  • __proto__ 접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아니라 Object.prototype의 프로퍼티입니다. 모든 객체는 상속을 통해 Object.prototype.__propto__ 접근자 프로퍼티를 사용할 수 있습니다.
const person = { name : 'jeon'}

// person 객체는 __proto__ 프로퍼티를 소유하지 않습니다.
// person.__proto__를 사용못하나? 체인으로 사용은 할 수 있지 않나?
// 프로퍼티 체인이 적용되어 사용 가능합니다.
console.log(person.hasOwnProperty('__proto__')); // fasle

// __proto__ 프로퍼티는 모든 객체의 프로토타입 객체인 Object.prototype의 접근자 프로퍼티입니다.
console.log(Object.getOwnPropertyDescriptor(Object.proptotype, '__proto__'));
// { get: f, set: f, enumerable: false, configurable: true}

// 모든 객체는 Object.prototype의 접근자 프로퍼티 __proto__를 상속받아 사용할 수 있습니다.
// person.__proto__ === Object.prototype // true
console.log({}.__proto__ === Object.prototype) // true
  • __proto__를 접근자 프로퍼티를 통해 프로토타입에 접근하는 이유는 상호참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위해서 입니다. 아무런 체크 없이 무조건적으로 프로토타입을 교체할 수 없도록 __proto__접근자 프로퍼티를 통해 프로토타입에 접근하고 교체하도록 구현되어 있습니다.
const parent = {}
const child = {}

child.__proto__ = parent; 
parent.__proto__ = child; // TypeError: Cycle __proto__ value
// 무한루프에 빠지게 됩니다.
  • __proto__를 접근자 프로퍼티를 직접 사용하는 것을 권장하지 않습니다. obj.__proto__보다 Object.getPrototypeOf()사용을 권장합니다.
// obj는 프로토타입 체인의 종접입니다.
// 따라서 Object.__proto__를 상속받을 수 없습니다.
const obj = Object.create(null);

console.log(obj.__proto__) // undefined

console.log(Object.getPrototypeOf(obj)) // null

// 취득 get , 교체 set
const obj2 = {};
const parent = { x: 1 };
Object.getPrototypeOf(obj2) // obj.__proto__
Object.setPrototypeOf(obj2, parent) //obj.__proto__ = parent

console.log(obj2.x) // 1

prototype 소개

함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킵니다.

// 함수 객체는 prototype 프로퍼티를 소유합니다.
(function () {}).hasOwnProperty('prototype'); // true

// 일반 객체는 prototype 프로퍼티를 소유하지 않습니다.
({}).hasOwnProperty('prototype'); // false

non-constructor 인 화살표 함수와 ES6 메서드 축약 표현으로 정의한 메서드는 prototype프로퍼티를 소유하지 않으며 프로토타입도 생성하지 않습니다.

// 화살표 함수는 non-constructor 함수입니다.
const Person = name => {
 this.name = name
}
// non-constructor는 prototype 프로퍼티를 소유하지 않습니다.
Person.hasOwnProperty('prototype') // false
Person.prototype // undefined

// ES6의 메서드 축약 표현으로 정의한 메서드는 non-constructor입니다.
const obj = {
	foo(){}
}
// non-constructor는 prototype 프로퍼티를 소유하지 않습니다.
obj.foo.hasOwnProperty('prototype') // false
obj.foo.prototype // undefineds

생성자 함수로 호출하기 위해 정의하지 않은 일반 함수도 prototype 프로퍼티를 소유하지만, 객체를 생성하지 않는 일반 함수의 prototype 프로퍼티는 아무런 의미가 없습니다.

모든 객체가 가지고 있는(엄밀히 말하면 Object.prototype으로부터 상속받은) proto 접근자 프로퍼티와 함수객체만이 가지고 있는 prototype 프로퍼티는 결국 동일한 프로토타입을 가리킵니다. 하지만 이들 프로퍼티를 사용하는 주체가 다릅니다.

__proto__ : 프로토타입의 참조, 모든 객체가 소유, 모든 객체가 사용 주체, 객체가 자신의 프로토타입에 접근 또는 교체 하기위해 사용합니다.
prototype : 프로토타입의 참조, constructor가 소유, 생성자 함수가 사용 주체, 생성자 함수가 자신이 생성할 객체(인스턴스)의 프로토타입을 할당하기 위해 사용합니다.

생성자 함수로 인스턴스가 생성될 때, constructor로 생성하게 되는데 이때, prototype 프로퍼티를 만들고 constructor 에 자신을 참조하고 있는 생성자 함수를 가리킵니다.

마치며 🍺

__proto__prototype에 대해 알아 보았습니다.
간단하게 요약해보자면 __proto__prototype은 동일한 것을 가리킵니다.
하지만 prototype은 생성자 함수에 의해 인스턴스를 생성될 때 생성되고,그 값이 유의미합니다.
그렇게 생성된 prototype 프로퍼티에 constructor는 생성자 함수를 가리키고 있습니다.

함께하면 좋은 글 😍

728x90