Skip to content

prototype (1) : __proto__ 접근자 프로퍼티

관리인
관리인May 6, 20254 min read

프로토타입 객체 또는 프로토타입은 객체 간 상속을 구현하기 위해 사용된다. 프로토 타입은 어떤 객체의 상위, 즉 부모 객체의 역할을 하는 객체로서 다른 객체에 공유 프로퍼티와 메서드를 를 제공한다. 프로토타입을 상속 받은 하위 객체는 상위 객체의 프로퍼티를 자신의 프로퍼티처럼 사용할 수 있다.

 

모든 객체는 [[property]] 라는 내부 슬롯을 가지며, 이 내부 슬롯의 값은 프로토타입의 참조이다. null인 경우도 있다. [[Prototype]] 슬롯에 저장되는 프로토타입은 객체 생성 방식에 의해 결정된다. 즉, 객체가 생성될 때 객체 생성 방식에 따라 프로토타입이 결정되고 [[Prototype]] 슬롯에 저장된다.

 

예를 들어 객체 리터럴에 의해 생성된 객체의 프로토타입은 Object.prototype이고 생성자 함수에 의해 생성된 객체의 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩 되어 있는 객체다.

 

예를 들어 const person = { name: 'cha'} 라고 선언했다면, 그 프로토타입은 Object.prototype이 된다.

 

모든 개체는 하나의 프로토타입을 갖는다. 그리고 모든 프로토타입은 생성자 함수와 연결돼 있다. 즉 객체와 프로토타입은 생성자 함수와 연결돼 있다.

 

[Prototype]] 내부 슬롯에는 직접 접근할 수 없지만,  proto 접근자 프로퍼티를 통해 자신의 프로토타입, 즉 자신의 [[prototype]] 내부 슬롯이 가리키는 프로토타입에 간접적으로 접근할 수 있다. 그리고 프로토타입은 자신의 constructor 프로퍼티를 통해 생성자 함수에 접근할 수 있고 생성자 함수는 자신의 prototype 프로퍼티를 통해 프로토타입에 접근할 수 있다.

 

즉, 모든 객체는 proto 접근자 프로퍼티를 통해 프로토타입을 가리키는 [[prototype]] 내부 슬롯에 접근할 수 있다.

 

---

 

prototype 접근자 프로퍼티

 

내부 슬롯은 프로퍼티가 아니다. 따라서 자바스크립트는 원칙적으로 내부 메서드에 직접적으로 접근하거나 호출할 수 있는 방법을 제공하지 않는다. 단, 일부 내부 슬롯과 내부 메서드에 한하여 간접적으로 접근할 수 있는 수단을 제공한다. 위에서도 언급했듯이 proto 접근자를 사용해 간접적으로 내부 슬롯인 [[Prototype]]에 접근하여 그 안에 들어 있는 값인 프로토타입에 접근할 수 있다.

 

접근자 프로퍼티인 proto(Object.는 그 자체로는 값을 갖지 않는다. 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용되는 접근자 함수, 즉 [[Get]], [[Set]] 프로퍼티 어트리뷰트로 구성되어 있다.

Object.prototype의 접근자 프로퍼티인 proto는 getter/setter 함수라고 부르는 접근자 함수를 통해 내부 슬롯의 값인 프로퍼티를 취득하거나 할당한다. 따라서 proto를 통해 프로토타입에 접근한다면, 내부적으로는 proto가 가진 get함수(get proto)를 사용하는 것이다. 새로운 프로토타입을 할당할 때에는 proto가 가진 setter함수(set __proto_)를 사용한다.

 

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

//getter(get __proto__) 사용gkdu obj 객체의 프로토타입을 가져온 상태
obj.__proto__;

//setter(set __proto__) 사용하여 새로운 값을 할당
obj.__proto__ = parent; 

console.log(obj.x); // 1

 

 

proto 접근자 프로퍼티는 상속을 통해 사용된다.

proto 접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아니라 Object.prototype의 프로퍼티다. 모든 객체는 상속을 통해 Object.prototype.__proto__ 접근자 프로퍼티를 사용할 수 있다.

 

Object.prototype

모든 객체는 프로토타입의 계층 구조인 프로토타입 체인(prototype chain)에 묶여있다.  자바스크립트 엔진은 객체의 프로퍼티와 메서드에 접근하려고 할 때, 해당 객체에 접근하려는 프로퍼티가 존재하지 않는다면, proto 접근자 프로퍼티가 가리키는 참조를 따라 자신의 부모역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다. 프로토타입 체인의 종점, 즉 프로토타입 체인의 최상위 객체는 Object.prototype이며 이 객체의 프로퍼티와 메서드는 모든 객체에 상속된다.

 

 

proto 접근자 프로퍼티를 통해 프로토타입에 접근하는 이유: 순환참조를 막기 위해서

[[Prototype]] 내부 슬롯의 값, 즉 프로토타입에 접근하기 위해 접근자 프로퍼티를 사용하는 이유는 상호 참조에 의해 프로토타입 체인이 새성되는 것을 방지하기 위해서이다. 이를 지키기 위해 프로토타입 체인은 단방향 링크트 리스트로 구현되어야 한다. 만약 proto 접근자를 사용하지 않고도 프로토타입을 교체할 수 있다면 무한루프 발생 가능성이 높아진다. 

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

// child 프로토타입을 parent로 설정
child.__proto__ = parent;

// parent 의 프로토타입을 child로 설정
parent.__proto__ = child; // 순환참조 에러 발생.

 

 

 

proto 접근자 프로퍼티를 코드 내에서 사용하는 것은 권장되지 않는다.

모든 객체가 proto프로퍼티를 사용할 수 있는 것은 아니기 때문이다. Object.prototype을 상속받지 않는 객체를 생성할 수도 있기 때문에 proto 접근자 프로퍼티를 사용할 수 없는 경우기 발생한다. 따라서 proto 접근자 프로퍼티 대신 아래 메서드를 사용하는 것이 권장된다.

 

- Object.getPrototypeOf : 프로토타입의 참조를 취득하려는 경우

- Object.setPrototypeOf : 프로토타입을 교체하려는 경우

 

// Object.__proto__를 상속받지 못하는 경우
const obj = Object.create(null);

console.log(obj.__proto__) // undefined

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

 

const ob = {};
const parent = { x:1 };

Object.getPrototypeOf(obj); // obj.__proto__

Object.setPrototypeOf(obj, parent); // obj.__proto__ = parent ; 

console.log(obj.x); // 1