본문 바로가기
창고(2021년 이전)

[JS] OOP - Inheritance patterns_상속

by 측면삼각근 2019. 11. 21.
728x90
반응형

OOP의특징

  1. 추상화
  2. 캡슐화
  3. 상속
  4. 다형성

이 글은 상속(Inheritance)에 대한 수업 정리가 될것이지만, 객체지향의 특성상 다른 특징과 함께 학습하는 것이 필수적이다.
상속은 다른 클래스가 가지고 있는 멤버(부모 클래스의 필드, 메소드)들을 새로 작성할 클래스에서 직접 만들지 않고 상속을 받음으로써 새 클래스가 자신의 멤버처럼 사용 할 수 있는기 능이다.
상속은 클래스의 재사용, 연관된 일련의 클래스들에 대한 공통적인 규약 정의를 위함이다.
장점은아래와같다.

  1. 보다 적은 양의 코드로 새로운 클래스 작성 가능하다는것
  2. 코드를 공통적으로 관리하기 때문에 코드의 추가 및 변경이 용이하다는것
  3. 코드의 중복을 제거하여 프로그램의 생산성/유지 보수에 기여

Prototype chain - 사양

Js : JavaScript 는 프로토 타입의 언어이다.

Js가 OOP를 생각하고 만든 언어는 아니지만, OOP가 보편적인 개발론이기 때문에 프로토타입을 활용하여 OOP를 구현하고자 노력하였다. ES6부터 class라는 키워드를 통하여 본격적으로 OOP를 지원하기 시작하였다.

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

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

var steve = new Human('steve');

 

  • Prototype : 모델의 청사진을 만들 때 쓰는 원형객체(Original form)
  • constructor :인스턴스가 초기화될 때 실행하는 생성자 함수
  • this :함수가 실행될 때, 해당 scope 마다 생성되는 고유한 실행 context (execution context)
    new 키워드로 인스턴스를 생성했을 때에는, 해당 인스턴스가 바로 this값이 됨

Ex) Array도 클래스이고, Instance를 만들때 new Array로 생성 

var Array = function(location){
	[native code]
}

Array.prototype.push = function(){};
Array.prototype.slice = functio(){};
...

var arr = new Array();

그래서 mdn의 문서에 또한 Array.prototype.find() 이런식으로 기재되어 있는 것이다.

 

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

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

var steve = new Human('steve');
steve.toString();
// [objcet Object]
// 모든 객체에 toString이라는 method 사용 가능

위 객체는 분명 toString이라는 메소드를 정의하지 않았지만, 사용가능하다.
steve 는 Human을 상속받았고, Human은 Object prototype을 상속받았기 때문이다.

이전 콘솔에 찍혔던 steve.__prototype__의  __prototype__에는 Objet라는 prototype이 들어있고 각종 메소드가 이미 구현되어있는 상태로 들어있다.

steve.__prototype__.__prototype__ === Objet.prototype

모든 객체는 상위단계는 Object가 있다. = 모든 객체는 Object를 상속받는다.

배열은 할당이 가능하다. 해당 object로 할당하지 않더라도, prototype을 할당하면 oject와 같이 작동한다.

var MyArray = function(){
}

MyArray.prototype = Array.prototype;

var myarr = new MyArray();
myarr.push(1); //MyArray [1]

그렇다면 상속을 어떻게 구현할것인가?

var Human = function(name){
  this.name = name;
}
human.prototype.sleep = function(){};

var steve = new Human('steve');  

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

var john = new Student('john');
// john.learn();
// john.sleep();//상속을 통한 구현이 가능하다.

 

방법1 - Deprecated

john.__proto__ = Human.prototype

지금은사용되지 않음

아래코드또한 객체의 참조를 바꾸어버린것이기 때문에 의미가 없다.

Student.prototype = Human.prototype
Student.prototype.learn = funciton(){}
// Student.prototype 과 Human.prototype이 같아진다.

 

방법2 - Object.create()

Student.prototype = Objcet.create(Human.prototype);
Student.prototype.learn = function(){}

Object.create 는 첫번째 인자로 들어가는 prototype을 기반으로 prototype을 만든다. =>(__prototype__)
하지만 이전에 연결해 두었던(new Human 으로) __prototype__이 증발.

Student.prototype = Object.create(Human.prototype);
Student.prototype.constructor = Student;
Student.prototype.learn = function(){}

이를 해결하기 위해서는 constructor 을 사용해야한다. (Js는 OOP를 위한 언어가 아니였기때문에)
또한 context가 전달되지 않기때문에(this 의 undefined 화) call을 통해 this를 지정해주어야한다.

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

Human.prototype.sleep = function(){
  console.log(this.name + ' is sleeping ...');
}

var steve = new Human('steve');

var Student = function(){
  Human.call(this, name); // Human.apply(this, arguments)
  //constructor에 this를 전달해주어야함
}

Student.prototype = Object.create(Human.prototype);
Student.prototype.constructor = Student;
Student.prototype.learn = funciton(){};

var john = new Student('john');
john.learn();
john.sleep(); // john is sleeping...
steve instance of Human === true;

john instance of Student === true;
john instance of Human === true;

Class keyword, Super

class Human{
  constructor(name){
    this.name = name;
  }
  sleep(){
    return 'sleep';
  }
}

var steve = new Human('steve');

class Student extends Human{
  constructor(name){//자식class와 모양이 같다면 생략 가능
    super(name);
    //this전달부 super 로 대체
  }
  sleep(){
    return super.sleep();
    //상위 메소드 return
    // return super.sleep() + 'in the desk';
  }
  learn(){
  }
}

var john = new Student('john');
john.learn();
john.sleep();/sleep in the desk

위에서 prototype chain과 동일함!
하지만 prototype chain보다 훨씬 많이 쓰이게될이다.

OOP인만큼 다형성또한 구현된다.

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

Human.prototype.sleep = function(){
  console.log('zzz')
}

function Student(name){
  Human.apply(this, arguments);
}

Student.prototype.sleep = funciton(){
  Human.prototype.sleep.apply(this);
  //뒤개의 sleep method가 같은 context를 공유한다...
  console.log('자면안되!!!');
}

 


suepr의 속성 삭제 - delete 키워드 사용불가

class Base{
  constructor(){}
  foo(){}
}

class Derived {
  constructor(){}
  delete(){
    delete super.foo();
  }
}

//ReferenceError 발생
new Derived().delete();

super.prop사용

var obj1 = {
  method1() {
    console.log("method 1");
  }
}

var obj2 = {
  method2() {
   super.method1();
  }
}

Object.setPrototypeOf(obj2, obj1);
obj2.method2(); // "method 1"
반응형