본문 바로가기
Dev/JavaScript

[JavaScript] 객체 응용 - 프로토타입

by 5kdk 2022. 11. 20.

✔ 들어가며

자바스크립트 객체의 this, 생성자 함수, 프로토타입을 살펴본다.

다행히도 ES6에서 자바스크립트의 Class 문법이 추가되었다. 하지만, 자바스크립트의 Class 문법은 Prototype 기반으로 구현된 자바스크립트의 문법적 편의 기능일 뿐 엔진 내부적으로는 prototype 방식으로 작동되기 때문에, Class를 활용하더라도 this, 생성자 함수, 프로토타입의 개념과 작동방식을 짚고 넘어가 보려 한다.

 

마지막으로 프로토타입을 다루는 포스팅이다.

 

2022.11.13 - [Dev/JavaScript] - [JavaScript] 자바스크립트의 객체 응용 - this

2022.11.18 - [Dev/JavaScript] - [JavaScript] 자바스크립트의 객체 응용 - 생성자 함수(feat. 인스턴스)

 

 

 


👀 프로토타입(Prototype) 이란?

자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있다. 그리고 이것은 마치 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메서드를 상속받아 사용할 수 있게 한다. 이러한 부모 객체를 Prototype(프로토타입) 객체 또는 줄여서 Prototype(프로토타입)이라 한다. 

 

💡 exam

var student = {
  name: 'Lee',
  score: 90
};

// student에는 hasOwnProperty 메소드가 없지만 아래 구문은 동작한다.
console.log(student.hasOwnProperty('name')); // true

console.dir(student);

student 객체의 프로토타입

 

 

 

 constructor 프로퍼티

프로토타입 객체는 constructor 프로퍼티를 갖는다. 이 constructor 프로퍼티는 객체의 입장에서 자신을 생성한 객체를 가리킨다.

 

💡 exam 1

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

const kim = new Person('kim', 50);
const dk = new Person('dk', 10);

// Person() 생성자 함수에 의해 생성된 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(kim.constructor.name); // Person
console.log(dk.constructor.name); // Person

console.log(kim instanceof Person); // true
console.log(dk instanceof Person); // true

Person()이라는 생성자 함수로 생성된 객체 kim, dk가 있다. 이때 객체 입장에서 자신을 생성한 객체는 Person() 생성자 함수이며, 객체의 프로토타입 객체는 Person.prototype이다. 로토타입 객체 Person.prototype의 constructor 프로퍼티는 Person() 생성자 함수를 가리키고 있다.

 

💡 exam 2

const obj = {};
const arr = [];
const func = function () {};
const str = new String('str');

obj.constructor.name; // Object
arr.constructor.name; // Array
func.constructor.name; // Function
str.constructor.name; // String

obj instanceof Object; // true
arr instanceof Array; // true
func instanceof Function; // true
str instanceof String; // true

Object, Array, String 등 내부적으로 프로토타입 프로퍼티를 가지고 있기 때문에, 상속받은 메서드를 호출할 수 있던 것. 

ex) String : charAt(), slice() ..., Array : sort(), reduce(), map()... 등

 

 

 

 __proto__ 프로퍼티

__proto__는 ES5까지는 ECMAScript 사양에 포함되지 않은 비표준 접근자였다. 하지만 일부 브라우저에서 지원하기 때문에 호환성을 고려하여 ES6에서 __proto__를 표준으로 채택했다.  __proto__ 프로퍼티에 접근하면 내부적으로 Object.getPrototypeOf()가 호출되어 프로토타입 객체를 반환한다. 하지만 여전히 코드 내에서 __proto__보다는 Object.getPrototypeOf()의 사용을 권장한다.

 

 

mdn __proto__
__proto__Deprecated

 

 

 

 프로토타입 체인

프로토타입 체인은 __proto__의 특징을 이용하여, 부모 객체의 프로퍼티나 메서드를 차례로 검색하는 것을 의미한다.

자바스크립트는 특정 객체의 프로퍼티나 메서드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티 또는 메서드가 없다면 [[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메서드를 차례대로 검색한다. 이때 프로토타입 객체의 마지막을 프로토타입 체인의 종점(End of prototype chain)이라 한다.

 

💡 exam

const animal = {
	sayName() {
		return 'ANIMAL';
	},
};

animal.sayName();// ANIMAL

const dog = Object.create(animal);

dog.sayName(); // ANIMAL

Array의 프로토타입 체인

 

 

 

 프로토타입 확장

프로토타입 객체도 객체이므로 일반 객체와 같이 프로퍼티를 추가/삭제할 수 있다. 그리고 이렇게 추가/삭제된 프로퍼티는 즉시 프로토타입 체인에 반영된다.  

 

💡 exam

// Super Class
function Animal(name, sound) {
	this.name = name;
	this.sound = sound;
}

Animal.prototype.getInfo = function () {
	return (
		this.name +
		'가(이)' +
		this.sound +
		' 소리를 낸다.'
	);
};

// Sub Class
function Friends(name, sound) {
	Animal.call(this, name, sound); // 명시적 바인딩
}

Friends.prototype = Object.create( // 프로토타입 연결
	Animal.prototype,
);

Friends.prototype.constructor = Friends;

const dog = new Friends('개', '멍멍');
const cat = new Friends('고양이', '냐옹');

dog.getInfo(); // 개가(이)멍멍 소리를 낸다.
cat.getInfo(); // 고양이가(이)냐옹 소리를 낸다.

dog.constructor.name; // Friend
cat.constructor.name; // Friend

dog instanceof Friends; // true
dog instanceof Animal; // true

프로토타입 확장 (extends, 상속)
위의 예시처럼 Animal이라는 생성자 함수를 확장해서 Friends 생성자 함수를 만들고, Friends로 Animal에 있는 메서드와 속성을 그대로 확장하여 사용할 수 있다.

 

아래는 ES6에 표준화된 __proto__를 사용한 상속  권장x

// ES6
const parent = {
  name: 'parent',
  sayHi() {
    console.log('Hi! ' + this.name);
  }
};

const child = {
  // child 객체의 프로토타입 객체에 parent 객체를 바인딩하여 상속을 구현한다.
  __proto__: parent,
  name: 'child'
};

parent.sayHi(); // Hi! parent
child.sayHi();  // Hi! child

 

 

 


📖 요약

  • 자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있다
  • 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메서드를 상속받아 사용할 수 있다
  • 이러한 부모 객체를 Prototype(프로토타입) 객체 또는 줄여서 Prototype(프로토타입)이라 한다
  • constructor 프로퍼티는 객체의 입장에서 자신을 생성한 객체를 가리킨다
  •  __proto__ 프로퍼티에 접근하면 내부적으로 Object.getPrototypeOf()가 호출되어 프로토타입 객체를 반환한다
  • 프로토타입 체인은 __proto__의 특징을 이용하여, 부모 객체의 프로퍼티나 메서드를 차례로 검색하는 것을 의미한다
  • 프로토타입 객체도 객체이므로 일반 객체와 같이 프로퍼티를 추가/삭제할 수 있다

 

참고자료

 

https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

https://poiemaweb.com/js-prototype

https://poiemaweb.com/es6-enhanced-object-property

댓글