[JavaScript ES6] Prototype

Sooooooah·2023년 4월 25일

javaScript ES6

목록 보기
3/8

프로토타입이란?

자바스크립트는 프로토타입 기반의 언어이다. > 이를 기반으로 확장과 재사용성을 높일 수 있음.
객체의 프로토타입(원형)을 가지고 새로운 객체를 생성해가는 프로그래밍 방식. 생성된 객체는 자기자신의 프로토타입을 갖는다.

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

자바스크립트 함수의 내부와 객체간의 관계

  1. 함수가 만들어지고 수행이 되어지면...
  2. 내부에서
    1. 함수 자신과 예를 들면 ‘Animal 함수’ 자신과 그리고 자신과 같은 이름의 ‘Animal 프로토타입 객체’가 생성
    2. Animal 함수 멤버로 —> prototype 속성이 생성 —> 다른 곳에 생성된 같은 함수 이름의 ‘Animal 프로토타입 객체’를 가리킴(참조)
function Animal(){}

// Animal 함수      
// + prototype --> Animal 프로토타입 객체(참조)
// + run() --> XXX

// Animal 프로토타입 객체
// + constructor --> Animal 함수(참조)
// + run()
// 'Animal 프로토타입 객체' --> 생성자 함수와 new 연산자를 통해서 만들어내는 모든 객체의 원형이 되는 객체

let tiger = new Animal();
let lion = new Animal();
// new 연산자와 생성자 함수를 이용하여 객체 생성시 각 객체에는 __proto__ 속성이 자동으로 생성
  1. ‘Animal 프로토타입 객체’에 멤버 한 개를 추가하면 —> tiger, lion 객체들도 동시에 이 멤버를 공유해서 모두가 사용가능
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}
*/
// 부모의 메서드는 사용할 수 있으면서 메모리 할당량을 줄일 수 있다.

프로토타입 상속

  1. 자바스크립트는 프로토타입 상속에 기반을 둔 OOP 언어 ( Class 문법을 지원 )

  2. 상속의 필요성

    1. 가장 큰 목적 —> 재사용

    이미 부모쪽에서 정의된 속성과 메서드를 그대로 물려받아 재사용할 수 있다.

    새로운 기능을 추가해서 기존 기능에서 더 확장시킬 수도 있다.

  3. 프로토타입 체인

    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 이순신
  1. 빈 객체 생성 후 proto 속성에 원하는 객체를 할당
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 이순신
  • 자바스크립트는 자신에게 없는 특성(속성, 메서드)을 proto가 가리키는 원형(부모)에서 가져온다.
  • 이때 맨 하위 자식 객체에서부터 순차적으로 연결되어있는 원형을 찾아간다. —> 프로토타입 체인
  • 즉, proto 속성이 가리키는 원형(부모)이 바로 상속을 해준 부모. (해당 객체의 프로토타입(원형))

객체의 프로토타입 출력

function A(){}
let obj = new A();

console.log(obj.__proto__);
console.log(Object.getPrototypeOf( obj ));

new 연산자의 내부 동작

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
  • 생성자 함수와 new 연산자에 의해 새로운 객체 생성 —> 객체의 생성과 새로운 객체의 원형(프로토타입)을 쉽게 지정할 수 있다.
  • 괄호 안에 ( 111, 222 )와 같은 초기값을 생성 시 편리하게 지정 —> 새로운 객체 인스턴스를 생성

생성자 함수와 내부에서 처리되는 동작들

const animal = {
  name: "tiger",
  age: 20,
};
console.log(animal.name, animal.age); // tiger, 20
  • 비슷한 객체의 동물을 수십, 수백 개 만들어야 하는 상황이라면?

—> 같은 객체를 생성해주는 생성자 함수를 만들어놓고 사용

  1. 생성자 함수
  • 첫 글자는 관례적으로 대문자로 작성 —> Animal
  • 새롭게 생성되는 객체 자신을 가리키는 것 —> this
  • new 연산자를 사용해서 새로운 객체 생성 —> new를 안 붙이면 undefined 처리 —> 객체 생성시에는 new 연산자를 꼭 사용!
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);

생성자 함수 —> 같은 객체를 만들어내는 ‘공장’

  1. 생성자 함수의 내부 실행 과정
function Person(name, age) {
  // this = {}; --> this라는 빈 객체를 하나 생성한 후에 속성을 추가
  this.name = name;
  this.age = age;
  //   return this;
}

new 연산자를 사용하여 새로운 객체를 생성시에는 생성자 함수 내부에서 위와 같은 처리로 새로운 객체가 생성

프로토타입 객체의 속성

  1. constructor 속성

→ 함수(예: 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
  1. new 연산자에 의해 새롭게 생성된 객체 —> 인스턴스
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
profile
즐거운 서비스를 추구합니다.

0개의 댓글