자바스크립트는 프로토타입 기반의 언어이다. > 이를 기반으로 확장과 재사용성을 높일 수 있음.
객체의 프로토타입(원형)을 가지고 새로운 객체를 생성해가는 프로그래밍 방식. 생성된 객체는 자기자신의 프로토타입을 갖는다.
Prototype 객체는 new 연산자에 의해서 생성된 객체 —> 공유 프로퍼티, 메서드 등을 제공하기 위해서 사용된다.
const fruit = {name: 'apple'};
console.log(fruit.name); // apple
// 속성 추가
fruit.expiration = '20201234';
console.log(furit.expiration);
// 속성이 있는지 없는지 체크 --> hasOwnProperty() 메서드 사용
console.log(fruit.hasOwnProperty('expiration')); // true
console.log(fruit.hasOwnProperty('country')); // false
// hasOwnProperty() 메서드를 정의해주지 않았는데 어떻게 사용하는것인가?
console.log(fruit); // __proto__ : Object
function Animal(){}
// Animal 함수
// + prototype --> Animal 프로토타입 객체(참조)
// + run() --> XXX
// Animal 프로토타입 객체
// + constructor --> Animal 함수(참조)
// + run()
// 'Animal 프로토타입 객체' --> 생성자 함수와 new 연산자를 통해서 만들어내는 모든 객체의 원형이 되는 객체
let tiger = new Animal();
let lion = new Animal();
// new 연산자와 생성자 함수를 이용하여 객체 생성시 각 객체에는 __proto__ 속성이 자동으로 생성
Animal.prototype.run = function (){
return '동물이 뛴다.';
}
tiger.run(); // 동물이 뛴다.
lion.run(); // 동물이 뛴다.
// 부모(원형)에 있는 run()메서드를 tiger, lion 객체내에서 만들어버리면 --> 자식의 메서드가 적용
// tiger 객체내에 run() 메서드를 새롭게 추가.
tiger.run = function(){
return '호랑이가 뛴다.';
}
console.log(tiger.run()); // 호랑이가 뛴다.
console.log(lion.run()) // 동물이 뛴다.
프로토타입(원형)으로 생성된 객체들은 모두 이 ‘프로토타입 객체’의 멤버들에 접근이 가능하고 사용할 수 있다. —> 생성된 객체들과 공유 ( 프로토타입 상속 )
function Add(a, b){
this.a = a;
this.b = b;
this.plus = function(){
return this.a + this.b;
}
}
let add1 = new Add( 100,20 );
console.log(add1);
let add2 = new Add( 200,30 );
console.log(add2);
let add3 = new Add( 300,40 );
console.log(add3);
let add4 = new Add( 400,50 );
console.log(add4);
/*
Add {a:100, b: 20, plus: f}
Add {a:200, b: 30, plus: f}
Add {a:300, b: 40, plus: f}
Add {a:400, b: 50, plus: f}
*/
//-------------------------------//
function Add2(a, b){
this.a = a;
this.b = b;
}
Add2.prototype.plus = function(){
return this.a + this.b;
};
let newadd1 = new Add2(100, 20);
console.log( newadd1 );
let newadd2 = new Add2(200, 30);
console.log( newadd2 );
let newadd3 = new Add2(300, 40);
console.log( newadd3 );
let newadd4 = new Add2(400, 50);
console.log( newadd4 );
/*
Add {a:100, b: 20}
Add {a:200, b: 30}
Add {a:300, b: 40}
Add {a:400, b: 50}
*/
// 부모의 메서드는 사용할 수 있으면서 메모리 할당량을 줄일 수 있다.
자바스크립트는 프로토타입 상속에 기반을 둔 OOP 언어 ( Class 문법을 지원 )
상속의 필요성
이미 부모쪽에서 정의된 속성과 메서드를 그대로 물려받아 재사용할 수 있다.
새로운 기능을 추가해서 기존 기능에서 더 확장시킬 수도 있다.
프로토타입 체인
proto : 상속을 해준 부모(원형)를 가리킴(참조)
자식 객체가 부모 객체의 멤버(속성, 메서드)를 사용할 수 있다. —> 상속 받았다.
let obj1 = {
name : '홍길동',
age : 20,
sayHi : function(){console.log('Hi' + this.name);}
};
let obj2 = {
name : '이순신',
};
// __proto__ 속성이 가리키는 것을 바꿀 수 있는가?
obj2.__proto__ = obj1;
console.log( obj2.age ); // 20
obj2.sayHi() // Hi 이순신
let obj3 = {};
// obj3 객체의 원형은? --> Object(최상위, Object.prototype) --> null
obj3.__proto__ = obj2;
// --> obj2, obj1 모두 상속을 받아 사용 가능
// hasOwnProperty
console.log( obj3.hasOwnProperty('') );
console.log( obj3.name ); // 이순신
console.log( obj3.age ); // 20
obj3.sayHi(); // Hi 이순신
function A(){}
let obj = new A();
console.log(obj.__proto__);
console.log(Object.getPrototypeOf( obj ));
function Add(a,b){
this.a = a;
this.b = b;
}
Add.prototype.plus = function () {
return this.a + this.b;
};
// 내부 동작
const newObj = {};
newObj.__proto__ = Add.prototype;
Add.apply(newObj, [111, 222]); // 인자 값들을 하나로 묶어서 적용해줘야 함
console.log(newObj.plus()); // 333
// 새로운 객체 생성
// const add = new Add(111, 222);
// console.log(add.plus()); // 333
const animal = {
name: "tiger",
age: 20,
};
console.log(animal.name, animal.age); // tiger, 20
—> 같은 객체를 생성해주는 생성자 함수를 만들어놓고 사용
function Person(name, age) {
this.name = name;
this.age = age;
}
let p1 = new Person("홍길동", 20);
let p2 = new Person("이순신", 30);
let p3 = new Person("강감찬", 40);
생성자 함수 —> 같은 객체를 만들어내는 ‘공장’
function Person(name, age) {
// this = {}; --> this라는 빈 객체를 하나 생성한 후에 속성을 추가
this.name = name;
this.age = age;
// return this;
}
new 연산자를 사용하여 새로운 객체를 생성시에는 생성자 함수 내부에서 위와 같은 처리로 새로운 객체가 생성
→ 함수(예: Animal)를 가리킨다. —> 즉, 참조를 값으로 가지는 속성
서로가 참조 —> 서로가 연결고리 역할⭐
생성자 함수(Animal) <-> Animal 프로토타입 객체
+prototype <-> +constructor
function Animal(name, age) {
this.name = name;
this.age = age;
}
Animal.prototype.aaa = function () {
{
console.log("aaa");
}
};
function Animal2(name, age) {
this.name = name;
this.age = age;
}
Animal2.prototype.bbb = function () {
{
console.log("bbb");
}
};
let a1 = new Animal("tiger", 20);
al.aaa(); // aaa
a1.__proto__ = Animal2.prototype;
a1.aaa(); // error
al.bbb(); // bbb
function A() {}
const testObj = new A();
console.log(testObj.constructor); // A();
// testObj 인스턴스(객체)가 A로 생성된 것인지를 판별 —> instanceof
const testObj2 = {
name: "홍길동",
age: 20,
};
console.log(testObj instanceof A); // true
console.log(testObj2 instanceof A); // false
console.log(testObj2 instanceof Object); // true