본문 바로가기
Javascript

javascript Object Oriented Programming (js-prototype)

by reo.l 2021. 1. 19.

객체지향에 대하여 공부했다.

이제 javascript의 객체지향에 대해서 알아보자

es6전 javascript에는 class가 존재하지 않았다.

class가 존재하지 않기 때문에 상속 기능 또한 구현하지 못했다.

그래서 js에 존재하는 prototype을 이용해 객체지향을 흉내 내어 구현하였다.

이처럼 prototype을 이용하여 객체지향을 구현하는 과정을 subclassing 패턴이라 하고

패턴들 중 pseudoclassical 한 패턴에 대하여 설명하겠다.

pseudoclassical 패턴에 대하여 알아보기 전 짚어 봐야 할 개념이 있는데 prototype과 constructor이다. 

 

1. prototype

프로토타입은 객체와 객체 사이를 연결하는 데 있어서 특수한 역할을 하는 객체이다.

javascript에서 모든 함수가 만들어질때 이 프로토타입이 같이 생성이 된다. 

 

prototype이 있다!!

속성을 담고 있는 프로토타입은 생성자를 통해 객체가 만들어질 때 그 객체와 연결된다.

다시 말해 프로토타입은 객체와 객체를 연결하는 체인의 역할을 수행한다.

객체와 객체를 연결하는 과정을 보자

function People(){}
People.prototype.alive = true; //People의 프로토타입에 속성을 추가한다.

function Reo(){}
Reo.prototype = Object.create(People.prototype);
//Object.create을 이용하여 Reo의 프로토타입과 연결시켜준다.

let yuchang = new Reo();
console.log(yuchang.alive); // true

이 프로토타입을 이용하여 값을 공유하게 되면 상속 기능을 구현할 수 있게 된다.

 

 

2. constructor

생성자는 객체를 만드는 역할을 하는 함수이다.

javascript에서 함수는 단순한 로직의 묶음이 아닌 객체를 만드는 생성자 역할을 수행할 수 있다.

우리가 여태 아는 방식과 다르게 함수를 호출할 때 앞에 new 키워드를 붙이고 함수를 호출하면

함수가 실행되는 것이 아닌 새로운 객체(함수도 객체이다)를 만들고 리턴한다. 

 

function People(){} // 생성자

let reo = new People(); 
// People이라는 생성자를 호출하여 reo라는 instance를 생성하였다.
reo.name = 'yuchang';	
reo.greeting = function(){ 
    return 'Hi my name is '+this.name; 
}
reo.greeting     // Hi my name is yuchang

let sangrae = new People(); 
sangrae.name = 'sangrae';
sangrae.greeting = function(){
    return 'Hi my name is '+this.name; 
}
sangrae.greeting // Hi my name is sangrae

 

새로운 객체를 만들때 참조하는 것이 생성자 함수이다. 

이를 생성자 함수의 초기화를 이용하여 표현하면 더 간단해진다.

function People(name){ // 생성자 내에서 정의 -> 초기화라함
  this.name = name;
  this.greeting = function(){
      return 'Hi my name is '+this.name; 
  }   
}

var reo = new People('yuchang');
console.log(reo.greeting())     // Hi my name is yuchang

var sangrae = new People('sangrae');
console.log(sangrae.greeting()) // Hi my name is sangrae

생성자 함수 안에 프로퍼티와 메서드를 정의하고 객체를 생성하였더니 코드의 재사용성이 높아졌다.

 

 

이제 prototype을 이용하여 객체지향을 구현하는

subclassing 패턴 중 pseudoclassical 패턴에 대하여 설명하겠다.

function Human(name) {
  this.name = name
};

Human.prototype.sleep = function () {};

function Student(name) {};

Student.prototype.learn = function () {};

let reo = new Student();
reo.learn();
reo.sleep(); // reo.sleep is not a function

이제 연관이 없는 Human과 Student를 연결해보자

function Human(name) {
  this.name = name
};

Human.prototype.sleep = function () {
  return `${this.name} zzzz`
};

function Student (name) {};

Student.prototype = Object.create(Human.prototype) // prototype을 연결

Student.prototype.learn = function () {};

let reo = new Student('yuchang');
reo.learn();
reo.sleep(); // 오류가 생기지 않고 잘 작동한다!

프로토타입을 이용하여 두 객체를 이어 주니 오류가 생기지 않고 잘 작동한다.

하지만 여기 두 가지 문제점이 있다.

첫 번째 문제는 constructor 문제이다.

reo.__proto__.constructor 
// reo의 constructor를 찍어보니 [Function: Human]이 나온다. 

Student.prototype.constructor = Student 
// constructor를 명확히 해주기 위해 이러한 방법을 사용한다.

이제 다시 constructor를 찍어보자

reo.__proto__.constructor // [Function: Student] 잘 연결이 되었다!!

여기서 두 번째 문제이다. 이제 콘솔로 reo.sleep()을 찍어보자.

function Human(name) {
  this.name = name
};

Human.prototype.sleep = function () {
  return `${this.name} zzzz`
};

function Student(name) {};

Student.prototype = Object.create(Human.prototype)
Student.prototype.constructor = Student

Student.prototype.learn = function () {};

let reo = new Student('yuchang');

reo.learn();
console.log(reo.sleep()); // undefined zzzz

Human의 콘텍스트가 전달이 되지 않았다.

이를 위해 Student에서 this를 바인딩해줌으로써 Human에 콘텍스트를 전달해 준다.

function Human(name) {
  this.name = name
};

Human.prototype.sleep = function () {
  return `${this.name} zzzz`
};

function Student(name) {
  Human.call(this,name) // 이처럼 call 메서드로 this를 전달해 준다.
};

Student.prototype = Object.create(Human.prototype)
Student.prototype.constructor = Student

Student.prototype.learn = function () {};

let reo = new Student('yuchang');

reo.learn();
console.log(reo.sleep()); //yuchang zzzz 잘 실행이 된다.

 

이처럼 복잡한 관계로 얽혀 subclassing을 해왔다. 하지만 es6 개정 이후 이제는 class가 있기에 이러한 복잡한 과정은 필요가 없다.

 

 

 

댓글