
객체를 상속하기 위하여 Javascript에서 사용하는 방식
프로토타입(Prototype)은 사전적의미로 원형을 뜻하며 실제 제품을 만들기 전 대략적인 형태, 또는 집합체안 비슷한 특징끼리 모아 형태를 만든 것이다.
자바스크립트에서는 Prototype을 활용하여 다양한 객체들간 비슷한 특징들을 하나의 프로토타입으로 만들어 객체지향을 구현한다.
그래서 자바스크립트는 Prototype 기반의 객체지향 프로그래밍 언어라고 불린다.
자바스크립트에서 객체는 Object라는 공통의 Prototype을 포함하고 있다.
Object를 통해 객체가 가지고 있는 공통적인 속성들을 Prototype으로부터 상속받는다.
즉 모든 객체들은 단 하나의 Object Prototype을 상속한다.
또한 배열도 Object Prototype을 상속받은 Array Prototype을 상속받는다. 이를 통해 객체간 프로토타입 체인을 연결한다.

외부에서는 Prototype에 직접 접근이 불가능하다.
그래서 아래와 같은 방법으로 Prototype에 접근한다.
__proto__
Object.getPrototypeOf()
Object.setPrototypeOf()
생성자 함수에서의 prototype접근
const obj1 = {};
const obj2 = {};
console.log(obj1.__proto__ === obj2.__proto__); // true
주어진 객체 자신의 속성에 대한 속성 설명자
디스크립터(Descriptor)는 스코프의 렉시컬환경처럼 오브젝트의 상태를 가지고 있다.
각각의 오브젝트는 프로퍼티는 프로퍼티 디스크립터라고 하는 객체로 저장된다.
value : 키에 해당하는 값
writable : 값의 수정여부
enumerable : 값의 열거여부 (iterator 여부)
configurable : 값에 해당하는 속성들을 수정, 삭제 여부
모든 속성의 기본값은 true이다.
const dog = { name: '와우', age: 2};
// 1. 모든 속성값 출력
const descriptors = Object.getOwnPropertyDescriptors(dog);
console.log(descriptors);
// { name: { value: '와우', writable: true, enumerable: true, configurable: true },
// age: { value: 2, writable: true, enumerable: true, configurable: true } }
// 2. 특정 속성값 출력
const desc = Object.getOwnPropertyDescriptor(dog, 'name');
console.log(desc);
// { value: '와우', writable: true, enumerable: true, configurable: true }
// 3. 특정 속성값 정의 및 수정
Object.defineProperty(dog, 'name', {
value: '멍멍',
writable: false,
enumerable: false,
configurable: false,
})
console.log(dog.name); // 멍멍
console.log(Object.keys(dog)); // [ 'age' ]
delete dog.name;
console.log(dog.name); // 멍멍
// 4. 모든 속성값 정의 및 수정
const student = {};
Object.defineProperties(student, {
firstName: {
value: '영희',
writable: true,
enumerable: true,
configurable: true,
},
lastName: {
value: '김',
writable: true,
enumerable: true,
configurable: true,
},
fullName: {
get() {
return `${lastName} ${firstName}`;
},
set(name) {
[this.lastName, this.firstName] = name.split(' ');
},
configurable: true,
},
})
console.log(student); // { firstName: '영희', lastName: '김' }
Object.keys, values, entries : 객체의 키, 값, 혹은 둘다 가져오는 것const dog = { name: '와우', age: 2};
console.log(Object.keys(dog)); // [ 'name', 'age' ]
console.log(Object.values(dog)); // [ '와우', 2 ]
console.log(Object.entries(dog)); // [ [ 'name', '와우' ], [ 'age', 2 ] ]
in연산자, Object.hasOwnProperty() : 특정 오브젝트의 해당 키 존재 유무를 확인const dog = { name: '와우', age: 2};
console.log('name' in dog); // true
console.log(dog.hasOwnProperty('name')); // true
더 이상 변경될 수 없게 객체를 동결
Object.freeze(): 객체를 동결하여 추가, 삭제, 쓰기, 속성 재정의를 금지 (단, 얕은 복사만 해당)const mirrer = { name: 'mirrer' };
const dog = { name: '와우', age: 2, owner: mirrer };
Object.freeze(dog);
dog.name = '멍멍';
console.log(dog.name); // 와우
dog.color = 'brown';
console.log(dog.color); // undefined
delete dog.name;
console.log(dog.name); // 와우
mirrer.name = 'mirrer2';
console.log(dog.owner.name); // mirrer2
Object.seal() : 객체를 밀봉하여 추가, 삭제, 속성 재정의를 금지 (단 값의 수정은 가능)// const cat = Object.assign({}, dog);
const cat = { ...dog };
Object.seal(cat);
cat.name = '냐옹';
console.log(cat.name); // 냐옹
delete cat.age;
console.log(cat.age); // 2
Object.isFrozen, isSealed, isExtensible : 객체의 동결, 밀봉 여부 확인const mirrer = { name: 'mirrer' };
const dog = { name: '와우', age: 2, owner: mirrer };
Object.freeze(dog);
const cat = { ...dog };
Object.seal(cat);
console.log(Object.isFrozen(dog)); // true
console.log(Object.isSealed(cat)); // true
Object.preventExtensions : 객체의 확장, 추가 금지const tiger = { name: '어흥' };
Object.preventExtensions(tiger);
console.log(Object.isExtensible(tiger)); // false
tiger.name = '어흐응';
console.log(tiger.name); // 어흐응
delete tiger.name;
console.log(tiger.name); // undefined
tiger.age = 2;
console.log(tiger.age); // undefined
Object.create,call함수를 이용하여 프로토타입 상속을 구현
프로토타입을 베이스로한 객체지향 프로그래밍에서 상속은 다음과 같이 구현할 수 있다.
상속받을 객체의 Prototype을 Object.create함수로 부모와 연결
상속받을 객체의 생성자함수를 Object.call함수로 부모의 생성자 함수와 연결
// 부모 Animal객체
function Animal(name, color) {
this.name = name;
this.color = color;
}
Animal.prototype.print = function () {
console.log(`${this.name} ${this.color}`);
}
// 자식 Dog 객체
function Dog(name, color, owner) {
// super(name, color);
Animal.call(this, name, color);
this.owner = owner;
}
// Dog.prototype = Object.create(Object.prototype);
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.play = () => {
console.log('같이 놀자옹!!');
}
// 자식 Tiger 객체
function Tiger(name, color) {
Animal.call(this, name, color);
}
Tiger.prototype = Object.create(Animal.prototype);
Tiger.prototype.hunt = () => {
console.log('사냥하자!!');
}
const dog1 = new Dog('멍멍', 'brown', 'mirrer');
dog1.play(); // 같이 놀자옹!!
dog1.print(); // 멍멍 brown
const tiger1 = new Tiger('어흥', 'yellow');
tiger1.print(); // 어흥 yellow
tiger1.hunt(); // 사냥하자!!
instanceof 연산자를 사용하여 상속관계를 확인할 수 있다.
instanceof 연산자는 상속관계 여부를 Boolean으로 반환한다.
// 부모 Animal객체
function Animal(name, color) {
this.name = name;
this.color = color;
}
Animal.prototype.print = function () {
console.log(`${this.name} ${this.color}`);
}
// 자식 Dog 객체
function Dog(name, color, owner) {
Animal.call(this, name, color);
this.owner = owner;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.play = () => {
console.log('같이 놀자옹!!');
}
// 자식 Tiger 객체
function Tiger(name, color) {
Animal.call(this, name, color);
}
Tiger.prototype = Object.create(Animal.prototype);
Tiger.prototype.hunt = () => {
console.log('사냥하자!!');
}
const dog1 = new Dog('멍멍', 'brown', 'mirrer');
dog1.play();
dog1.print();
const tiger1 = new Tiger('어흥', 'yellow');
tiger1.print();
tiger1.hunt();
console.log(dog1 instanceof Animal); // true
console.log(dog1 instanceof Dog); // true
console.log(dog1 instanceof Tiger); // false
오브젝트는 단 하나의 prototype만을 가리킬 수 있다.
하지만 여러개의 함수들을 상속받아 사용하고 싶다면 Object.assign를 사용하여 객체의 프로토타입에 사용할 함수들을 복사할 수 있다.
const play = {
play: function () {
console.log(`${this.name} 놀아요!`);
}
}
const sleep = {
sleep: function () {
console.log(`${this.name} 자요ZzZ`);
}
}
function Dog(name) {
this.name = name;
}
Object.assign(Dog.prototype, play, sleep);
const dog = new Dog('멍멍');
console.log(dog); // Dog { name: '멍멍' }
dog.play(); // 멍멍 놀아요!
dog.sleep(); // 멍멍 자요ZzZ
Object.assign은 프로토타입뿐만 아니라 클래스에서도 사용가능
const play = {
play: function () {
console.log(`${this.name} 놀아요!`);
}
}
const sleep = {
sleep: function () {
console.log(`${this.name} 자요ZzZ`);
}
}
class Animal {}
class Tiger extends Animal {
constructor(name) {
super();
this.name = name;
}
}
Object.assign(Tiger.prototype, play, sleep);
const tiger = new Tiger('어흥!');
console.log(tiger); // Tiger { name: '어흥!' }
tiger.play(); // 어흥! 놀아요!
tiger.sleep(); // 어흥! 자요ZzZ
Object prototypes - Web 개발 학습하기 | MDN
모던 자바스크립트 Deep Dive
모던 JavaScript 튜토리얼