본문 바로가기
Web/Javascript

상속

by juein 2018. 2. 27.

[Chapter 5] 상속

- 상속의 유용한 점은 코드를 재사용 하는 것이다. 

  새로만든 클래스가 기존 클래스와 매우 유사하다면 상속을 통해 다른 부분만 구현해낼수 있다


- 자바스크립트는 클래스를 기반으로 하는 상속을 지원하지 않고

  프로토타입 체인을 이용하여 상속을 구현해낸다. (객체가 다른 객체로 바로 상속 된다) 이러한 상속의 구현방식으로 여러가지 패턴이 있다.



01] 의사 클래스 방식(Pseudoclassical)

- 의사 클래스는 클래스처럼 행동하지만 진짜 클래스는 아니다.


- 클래스가 없는 자바스크립트가 클래스 기반의 상속 방식을 흉내내는 것. 


- 생성자 함수를 통해서 객체를 생성해야 한다.

//동물 생성자 함수 정의
var Animal = function( name ){
  this.name = name;
}

//동물의 이름 속성 추가
Animal.prototype.get_name = function(){
  return this.name;
};

//console.dir(Animal);

//myAnimal을 Animal의 새 인스턴스로 대체
var myAnimal = new Animal( 'morrie' );   // <-- 객체를 생성하기 위해 만들어지는 또 다른 객체

console.log( '내 애완동물 이름은 ' + myAnimal.get_name() + '입니당' );


//의사 클래스
var Cat = function( name ){
  this.name = name;
  this.saying = 'meow';
}

//Cat 프로토타입을 Animal의 새 인스턴스로 대체
Cat.prototype = new Animal('test cat');

console.dir(Cat);

var morrie = new Cat( 'morrie' );

console.log( morrie.name + '의 소리 : ' + morrie.saying );     // morrie 의 소리 : meow 출력


- 의사 클래스는 자바스크립트에 익숙하지 않은 프로그래머들에게 편안함을 제공하지만  자바스크립트의 장점을 가리게 되는 법이다.


- 위 예제의 문제점으로 모든 객체의 속성이 public 이라는 것과,

  생성자 함수 new 연산자로 실행하지 않으면 this 바인딩에 의해 this는 새로운 객체에 바인딩 되지 않고 전역객체(window)에 연결된다는 문제가 있다. 




02] 객체를 기술하는 객체(Object Specifiers)

- 생성자가 매우 많은 매개변수를 갖게되는 경우 생성자가 인수를 받는 대신에  객체를 기술하는 하나의 객체를 받도록 정의 할 수 있다.

var test = testFunc( n, c, i, s );

위 코드 아래와 같이 작성 할 수 있다.

var test = testFunc({
 name : n,
 color : c,
 idx : i,
 state : s
});

- 인수는 꼭 순서를 맞출 필요가 없으며, 생성자가 기본값 설정을 잘 하고 있다면 인수를 생략 할 수도 있다




03] 프로토타입 방식

- 프로토타입에 기반한 패턴에서는 클래스가 필요 없다.


- 프로토타입에 의한 상속은 클래스에 의한 속성보다 더 간단하다.

//객체 리터럴로 동물객체 생성
var animal = {
  name : '',
  says : function(){
    return this.saying;
  }
};

//Object.create 메소드로 인스턴스를 만들 수 있다.
//create() : 넘겨받은 객체를 프로토타입으로 하는 새로운 객체를 생성하는 메소드
var my_cat = Object.create(animal);
var my_dog = Object.create(animal);

console.dir(my_cat); 
console.dir(my_dog); 

//상속받아온 인스턴스에 원하는 속성이나 메소드 추가
my_cat.name = 'morrie';
my_cat.saying = 'meow';

my_dog.name = 'dogidogi';
my_dog.saying = 'bow wow';

console.dir(my_cat); 
console.dir(my_dog); 



04] 함수를 사용한 방식

- 프로토타입에 의한 상속 패턴의 한가지 단점은 private 속성을 가질수 없다는 것이다. (private 변수, private 메소드도 모두 생성할 수 없다.)


- 함수형 패턴은 유연성이 매우 좋다.  이 패턴은 의사 클래스 패턴보다 작업량이 적고 캡슐화와 정보은닉에 사용 할 수 있다.

//객체 생성
var animal = function( spec ){
  
  var that = {}; //필요한 private 변수
  
  // 새로운 객체를 할당하고 메소드를 추가. 
  that.get_name = function(){
    return spec.name;     // <-- private 속성이다
  };

  that.says = function(){
    return spec.saying;   // <-- private 속성이다
  }

  // 새로운 객체 반환
  return that;
  
};

var myAnimal = animal( {name : 'morrie'} ); 
console.log( myAnimal.get_name() );



05] 클래스 구성을 위한 부속품

- 제품을 만들 때 부속품을 가져다 조립을 하듯이 객체를 구성할 때도 같은 방법으로 할 수 있다

var eventtuality = function ( that ) {
  
  var registry = { };
  that.fire = function (event) {  
     var array, func, handler, i, type = typeof event === 'string' ? event : event.type;
     // 해당 이벤트에 상응하는 처리 함수 목록 배열이 있으면
     // 루프를 돌면서 이 배열에 등록돼 있는 모든 처리 함수를 실행 시킨다.
     if ( registry.hasOwnProperty(type)){
       array = registry[type];
       for ( i = 0 ; i < array.length; i += 1){

         handler = array[i];
          func = handler.method;
          // 처리 함수 배열에 속하는 항목 하나는 처리 함수인 method 와 매개변수인 
          // parameters 라는 배열로 구성됨, method 가 함수 자체가 아니라 이름이면,
          // this 에서 해당 함수를 찾음.
          if ( typeof func === 'string' ) {
              func = this[func];
          }
          // 처리 함수 호출, parameters 가 있으면 이를 넘김. 없다면 event 객체를 넘김
         func.apply( this, handler.parameters || [event] );
       }
     }
     return this;
  };
  that.on = function (type, method, parameters) {
     // 이벤트 등록 handler 항목을 만들고 해당 이벤트 타입의 배열에 추가
     // 만약 기존에 배열이 없다면 해당 이벤트 타입에 대해 새로운 배열 생성
     var handler = {
            method : method,
            parameters : parameters
     };
     if ( registry.hasOwnProperty ( type ) ) {
        registry[type].push(handler);
     } else { 
        registry[type] = [handler];
     }
     return this;
  };
  return that;
  
};

var oDiv = eventtuality(document.getElementById('divTest'));
oDiv.on('click', function (){ 
  console.log('test') 
});

var oButton = eventtuality(document.getElementById('button_test'));
oButton.on('click', function(){
  console.log('test_button');
});
//HTML
<div id="divTest" onclick="this.fire(event)"></div>
<button id="button_test" onclick="this.fire(event)">test</button>
//CSS
#divTest{
  width: 100px;
  height: 100px;
  border: 1px solid #ddd;
  cursor:pointer;
}


'Web > Javascript' 카테고리의 다른 글

정규표현식  (0) 2018.02.28
배열  (0) 2018.02.28
콜백, 모듈, 커링, 메모이제이션  (0) 2018.02.27
함수 - (스코프, 클로저)  (0) 2018.02.26
함수  (0) 2018.02.26

댓글