객체지향 constructor, prototype

Tae_Tae·2024년 7월 15일

constructor


Object를 안전하게 많이 복사해 만들 수 있는 문법

예를들어 학생 list를 만들어야하다고 하면

var 학생1 = { name : 'Kim', age : 15 };
var 학생2 = { name : 'Park', age : 15 };
...

이렇게 하드 코딩하기보다 constructor문법을 사용하면 더 간단하다.

function constructor(){
  this.name = 'kim';
  this.age = 15;
}

var 학생1 = new constructor();

constructor 문법은
function을 선언하고 내부에 this.원하는 object값을 넣으면 된다.
this는 새로생성되는 오브젝트(인스턴스)를 뜻한다.

사용 방법은 변수 이름 = new constructor 이름() 이렇게 사용하면 된다.

비슷하거나 독립적인 object 자료를 여러개 만들 때 코드의 양이 줄어들어 사용하는 문법이다.

constructor에 function 추가 가능

function constructor(){
  this.name = 'kim';
  this.age = 15;
  this.sayHi = function(){
    console.log('안녕하세요' + this.name + ' 입니다');
  }
}

var 학생1 = new constructor();
학생1.sayHi();

name의 속성을 각각 다르게 해서 object들을 만들고 싶다.하면
함수의 파라미터를 생각하면된다.

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

var 학생1 = new constructor('kim', 15);
var 학생2 = new constructor('Lee', 16);

console.log(학생1); // name : 'kim', age : 15
console.log(학생2); // name : 'Lee', age : 16

함수에 파라미터를 추가한다면 앞으로 constructor라는 함수를 쓸 때마다
파라미터자리에 뭔가 데이터를 넣어서 실행할 수 있는 것이다.

prototype


위에서 다룬 내용은 객체지향 용어로 상속(inheritance)이라고 한다.

constructor가 가진 name, age 속성들을 그대로 물려받아서 오브젝트를 하나 뽑아주는게
뭐 재산 물려주는 상속과 비슷하다고 해서 상속이라고 부릅니다.
(그래서 상속해주는 것은 부모, 상속받는 오브젝트들은 자식이라고 많이 비유해서 부른다.)

constructor을 만들면 prototype이라는 항목이 생성되는데

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

var 학생1 = new constructor('kim', 15);
var 학생2 = new constructor('Lee', 16);

console.log(constructor.prototype);

console창을 확인해보면 무엇인가 출력된다.

prototype(원형)은 자식들이 물려받을 수 있는 유전자라고 생각하시면 되는데

constructor.prototype은 constructor의 유전자이다.
constructor.prototype 에 뭔가 변수나 함수가 들어가있다면
constructor로부터 생성되는 새로운 오브젝트들(자식들)은 전부 그걸 그대로 물려받아 쓸 수 있다.

function constructor(){
  this.name = 'Kim';
  this.age = 15;
}

constructor.prototype.gender = '남';

var 학생1 = new constructor();
var 학생2 = new constructor();

console.log(학생1.gender); //'남'이 출력됩니다

constructor의 prototype이라는 곳에 { gender : '남' } 이라는 key/value 한 쌍을 저장했습니다.
(prototype은 저렇게 오브젝트 자료형 다루듯이 하면 된다.)

constructor의 prototype(원형)에 gender을 추가한 것이므로
constructor로부터 생성되는 자식들은 gender라는 속성을 사용할 수 있다.

  • prototype에는 값을 여러개 부여할 수도 있고 심지어 함수도 집어넣으실 수 있고 object 자료처럼 다루면된다.

  • prototype에 추가된 데이터들은 자식들이 직접 가지는게 아니라 부모만 가지고 있다.

prototype의 작동 원리


이러한 prototype의 작동원리를 설명하면

java script에서는 오브젝트에서 데이터를 추출할 때 확인하는 순서가 있다.

function constructor(){
  this.name = 'Kim';
  this.age = 15;
}

constructor.prototype.gender = '남';
var 학생1 = new constructor();
var 학생2 = new constructor();

console.log(학생1.gender); //'남'이 출력됩니다

위 코드를 다시 사용하여 설명해보면

  1. 학생1에 직접 gender값이 있는가
  2. 없다면 부모(원형, prototype)에 gender라는 값이 있는가
  3. 없다면 부모의 부모에 있는가
  4. ...(찾을 때까지 반복)

자바스크립트 array, object 들에는 붙일 수 있는 내장함수들이 많습니다.
sort, push, toString, map, forEach 등 이런 것들을 array에 붙여서 사용가능한데 그 이유는

var arr = [1,2,3];
console.log( arr.toString() ); //가능

내가 만든 array는 부모 기계로 부터 뽑은게 아닌데 뭔소리하는 거냐고요?

여러분 실은 array나 object 자료형 만드실 때 부모가 있긴 있습니다.

var arr = [1,2,3];
var arr = new Array(1,2,3);

▲ 위 코드 두줄은 같은 완전 똑같은 의미인데
위는 사람이 array 만드는 방식, 밑은 컴퓨터가 array 만드는 방식입니다.
내부적으로는 저렇게 new 키워드를 항상 이용해서 array/object를 만들어줍니다.

그럼 new Array()는 Array라는 constructor로부터 자식을 하나 새로 뽑아주세요 라는 뜻이다.

그래서 Array로부터 생성된 자식들은 Array의 원형에 부여되어있는 함수, 데이터들을 자유롭게 사용하실 수 있습니다.

한번 Array의 prototype을 확인해보면

console.log(Array.prototype);

평소에 쓰던 sort, map, push, forEach 이런 것들이 나온다.
그래서 Array의 자식들은 전부 이런 함수들을 쉽게 가져다 쓸 수 있는것이다.

Object 자료형도 똑같이 new Object() 이런 식으로 만들어주기 때문에 부모의 prototype에 있던 함수들을 자유롭게 사용가능합니다.

prototype으로 상속, constructor로 상속의 차이점

자식들이 값을 직접 소유하게 만들고 싶으면 constructor
부모만 가지고 있고 그걸 참조해서 쓰게 만들고 싶으면 prototype

보통은 그래서 상속할 수 있는 함수 같은 것들은 prototype으로 만든다.

prototype의 특징

  1. prototype은 constructor 함수에만 몰래 생성된다..
    일반 object, array엔 prototype이 없다.
    그럼 일반 object 같은걸 상속하고 싶으면 constructor 함수를 만들던가.. 아니면Object.create()를 쓰거나 class를 쓰거나 셋 중 하나 하시면 됩니다.

  2. 부모 유전자를 찾고 싶다면 __proto__를 출력해보시면 됩니다.
    부모로부터 생성된 자식 object들은 __proto__라는 속성이 있습니다.
    이걸 출력해보시면 부모의 prototype이 출력됩니다.
    그래서 __proto__는 부모의 prototype과 같은 의미입니다.

function 기계(){
  this.name = 'Kim';
  this.age = 15;
}
var 학생1 = new 기계();
console.log(학생1.__proto__);
console.log(기계.prototype);

학생1.__proto__

기계.prototype

각각 출력해보시면 똑같은게 나오죠?

아무튼 그래서 "__proto__는 부모 prototype을 의미한다" 라고 알아두시면 되겠습니다.

그냥 __proto__는 내 부모 유전자가 뭔지 유전자 검사하고 싶을 때 쓸 수 있는 그런 값이라고 생각하시면 되겠습니다.

  1. __proto__를 직접 등록하면 object끼리 상속기능을 구현가능합니다.
    __proto__는 부모의 prototype을 의미한다 라고 했습니다.

그럼 어떤 object에다가 __proto__를 강제로 하나 설정해버리면 어떻게 될까요?
오 이런 부모님이 생겨버립니다.

var 부모 = { name : 'Kim' };
var 자식 = {};

자식.__proto__ = 부모;
console.log(자식.name);

지금 부모와 자식 object를 하나씩 만들었습니다.

그리고 셋째줄에서 자식의 proto에 부모를 집어넣었습니다.

그럼 자식의 부모 유전자는 { name : 'Kim' } 이라는 오브젝트가 되는 것입니다.

그렇게 되면 자식은 이제 자식.name 속성을 자유롭게 사용할 수 있습니다.

상속기능 구현을 이렇게도 할 수 있군요.

  1. 실은 콘솔창에 prototype 정보들이 항상 출력됩니다.
function 기계(){
  this.name = 'Kim';
  this.age = 15;
}
기계.prototype.gender = '남';

var 학생1 = new 기계();

그럼 콘솔창에 name도 나오고 age도 나올 텐데

이상한 proto 이런 것도 나옵니다.


proto가 뭐랬습니까. 부모의 유전자라고 했죠?

그래서 이걸 항상 까보실 수 있습니다. 아마 기계.prototype이랑 똑같은 내용이 출력되겠죠.

그리고 기계.prototype의 proto도 조회가능합니다. (기계.prototype의 부모 유전자요)

이렇게 쭉 내 부모의 부모까지 탐색할 수도 있습니다.

탐색해보시면 모든 object 자료형의 조상은 Object() 라는 기계이며 (일명 Object.prototype)

모든 array 자료형의 조상도 Object()입니다. (중간에 Array()라는 부모도 있고요)

모든 함수 자료형의 조상도 Object() 입니다.

(그래서 자바스크립트는 모든게 다 Object라고 말하는 것입니다.)

0개의 댓글