JS Prototype

👀 Prototype이란?

자바스크립트는 프로토타입 기반의 언어이다.

 

클래스 기반 언어 -> 상속

프로토타입 기반 언어 -> 복제

 

진짜 복제가 아니라 프로토타입 링크를 통해 해당 객체를 참조하여 만드는 것이다.

 

자바스크립트에서는 원시타입(Number, String, Boolean, Symbol, Undefined, null)을 제외한 모든 참조 타입이 객체이다.

객체는 원형을 참조해서 새로운 객체를 생성하게 되는데, 그 때 프로토타입 링크인 __proto__가 같이 생성된다.

function Person() {}

var HeeDong = new Person();
var Guri = new Person();

Person이라는 함수가 정의 되고, Person 함수의 prototype 속성은 Person Prototype 객체를 참조한다.

반대로 Person Prototype 객체의 constructor 속성은 Person 함수를 참조한다.

Person Prototype 객체는 new 연산자와 Person 함수를 통해 생성되는 모든 객체의 원형이 된다.

따라서 HeeDong 객체와 Guri 객체의 proto 속성은 Person Prototype 객체를 참조한다.

 

🤔 Person Prototype 객체는 어디서 나왔을까?

함수라는 객체를 생성하면 그 객체에는 prototype이라는 object가 자동으로 생성된다.

prototype에는 다시 constructor라는 객체가 자동으로 생성되어 서로 참조하는 것이다.

 

객체 안에는 기본적으로 proto 속성이 존재하고, 이 속성은 prototype 객체를 참조한다.

prototype 속성은 생성자의 속성이고, proto 속성은 개별 객체의 속성이다.


👀 Prototype 객체란?

프로토타입 객체란 다른 객체의 원형이 되는 객체이다.

모든 객체는 자신의 프로토타입 객체에 접근할 수 있다.

같은 원형 가진 객체는 추가된 멤버를 사용할 수도 있다.

 

function Person(){}

var heedong = new Person();
var giuri = new Person();

Person.prototype.getType = function() {
	return '사람';
}

console.log(heedong.getType());		// 사람
console.log(guri.getType());		// 사람

prototype 속성을 이용해서 getType이라는 함수를 추가했고,

추가된 getType 함수는 같은 프로토타입 객체를 가진 heedong과 guri 객체에서도 사용이 가능하다.

 

🤔 만약 여기서 heedong의 getType 함수를 수정하고 age 변수를 추가하면 어떻게 될까?

heedong.getType = function() {
	return '사람아님';
}

heedong.age = 23;

console.log(heedong.getType());		// 사람 아님
console.log(guri.getType());		// 사람

console.log(heedong.age);		// 23
console.log(guri.age);			// undefined

생성된 객체로 멤버를 수정하면 해당 객체의 멤버를 수정하는 것이다.

따라서 같은 객체인 guri에는 영향을 미치지 않는다.

 

프로토타입 객체의 함수를 수정하고 싶은 것이라면 아래처럼 prototype 속성을 이용해서 수정해야 한다.

Person.prototype.getType = function() {
	return '사람아님';
}

 


👀 Prototype, [[ Prototype ]], constructor

헷갈리니까 한 번 정리하고 가자 ! ! !

 

- prototype 프로퍼티

함수 객체만 가지고 있는 프로퍼티이다.

Prototype 객체란 부모가 되는 객체이고 하위 객체들에게 물려줄 속성들이다.

 

- [[ Prototype ]] 프로퍼티 == __proto__ 프로퍼티

함수를 포함한 모든 객체가 가지고 있는 프로퍼티이다.

객체의 입자에서 부모가 되는 Prototype 객체를 가리킨다.

 

- constructor 프로퍼티

프로토타입 객체(=부모 객체)는 constructor 프로퍼티를 가진다.

constructor 프로퍼티는 생성된 객체의 입장에서 자신을 생성한 함수를 가리킨다.


👀 Prototype Chain

객체들 사이에 형성된 프로토타입 링크를 프로토타입 체인이라 한다.

특정 객체의 프로퍼티나 메소드에 접근 시,

__proto__가 가리키는 링크를 따라서 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메소드에 접근할 수 있다.

자바스크립트의 최종 원형 객체인 Object.prototype까지 탐색을 한 후, 값이 존재하지 않으면 undefined 반환한다.

 

따라서 __proto__는 객체와 객체를 연결하는 역할을 한다.

 

우리가 배열에 .length를 이용해 길이를 알아내거나 .sort를 통해 정렬을 할 수 있는 이유이다.

const arr = [1, 2, 3, 4, 5];

위와 같이 배열을 만들어도, new Array()로 배열이 생성되고,
arr은 Array라는 부모 객체를 가지게 된다.

 

콘솔 창을 통해 간단하게 확인해 볼 수 있다.


👀 프로퍼티 존재 확인

- in 연산자

const person = {
	name: 'heedonguri',
    age : 23
}

console.log('name' in person); 		// true
console.log('toString' in person); 		// true

 

- Object.prototype.hasOwnProperty

const person = {
	name: 'heedonguri',
    age : 23
}

console.log(person.hasOwnProperty('name')); 		// true
console.log(person.hasOwnProperty('toString')); 		// false

in 연산자와의 차이점은 고유 프로퍼티가 아닌, 상속받은 프로퍼티는 false로 처리한다.


👀 프로퍼티 열거

- for ... in 문

const person = {
	name: 'heedonguri',
    age : 23
}

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

위와 같이 출력된다.

 

for in 문은 프로토타입의 프로퍼티까지 열거되는데, 위에서 Object.prototype의 프로퍼티는 열거되지 않았다.

Object.prototype의 속성 값은 열거할 수 없도록 정의되어 있기 때문이다.

 

프로토타입의 프로퍼티까지 나오는 특징 때문에

Object.key / Object.values / Object.entries 메서드를 쓰는걸 권장한다.

위의 3가지 메서드는 객체의 프로토타입의 프로퍼티가 아닌,
객체 자체에 정의된 직접적인 프로퍼티만 반환한다!

 

- Object.Key 

객체 자신이 열거 가능한 프로퍼티 를 배열로 반환한다.

 

- Object.values

객체 자신이 열거 가능한 프로퍼티 을 배열로 반환한다.

 

- Object.entries

객체 자신이 열거 가능한 프로퍼티 키와 값을 쌍으로 배열로 반환한다.


👀 Prototype을 쓰는 이유

재사용성을 높이고 메모리 절약을 할 수 있다.

생성자 함수를 통해 객체를 생성하면 객체 마다 property와 method가 생성되는데, 이는 메모리 낭비로 이어진다.

Prototype을 사용하면 부모 객체 생성 시 한 번만 생성하게 되어 메모리를 절약할 수 있다.

 

이때, Object.create() 함수를 사용하여 객체를 생성하는 동시에 프로토타입 객체를 지정할 수 있다.

두번째 매개변수부터는 자식객체의 속성에 추가할 부분을 적어줄 수도 있다.

'JavaScript' 카테고리의 다른 글

JS Array와 Array 메소드  (0) 2024.08.26
JS Class  (0) 2024.08.13
JS closure  (0) 2024.08.07
JS This  (0) 2024.08.07
JS 동작원리  (0) 2024.08.05