[번역]간단한 자바스크립트 상속

원본 : http://ejohn.org/blog/simple-javascript-inheritance/

난 최근에 자바스크립트 상속에 관해 많은 일을 해왔다.

다시말해 “자바스크립트 책 안에서의 내 일“을 위해서, 그리고  다수의 다른

자바스크립트의 고전적인 상속 시뮬레이팅 기술에 대해 시험해왔다.

내가 보고 생각한 것 중 가장 좋아하는 것은 “base2“와 “Prototype“에 의해

사용된 구현이었다.

난 이런 기술들에서 간단하고, 재사용하고,어떤 의존성 없이 쉽게 이해할 수 있는 양식

가지는 기술을 뽑아내기를 원했다.

부가적으로, 난 간단하면서도 사용성이 높은 결과가 나오길 원했다.

여기 당신이 그것을 사용할 수 있는 예제가 있다.

var Person = Class.extend({
  init: function(isDancing){
    this.dancing = isDancing;
  },
  dance: function(){
    return this.dancing;
  }
});
var Ninja = Person.extend({
  init: function(){
    this._super( false );
  },
  dance: function(){
    // Call the inherited version of dance()
    return this._super();
  },
  swingSword: function(){
    return true;
  }
});

var p = new Person(true);
p.dance(); // => true

var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true

// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class

이 구현에 대해 주목해야 할 것들은..

  • 생성자 생성이 간단하다(이 경우 init method의 간단한 제공으로 트릭을 썼다)
  • new ‘class’의 생성을 위해 존재하는 클래스를 확장할 수 있다.
  • 하나의 조상(Class)으로부터 상속받은 모든 ‘classes’들은 클래스이다.
    그러므로, 새로운 클래스를 만들길 원한다면 그것은 Class의 sub-class일 것이다
  • 가장 도전적인 것 : 오버라이드 된 메서드에 접근하는 것도 제공된다
    (그들의 전적인 문맥에 맞춰) 당신은 this._super(), Person super-class에서
    init()과 dance()메서드를 호출하는 것을 사용하는 걸 볼 수 있다.

난 결과를 기쁘게 생각한다. 그것은 구조로서의 “classes”의 개념을 강화하는 데 도움을 줬고

간단한 상속을 유지하고, 슈퍼 메서드 호출을 허용한다.

-간단한 클래스 생성과 상속-

여기 25라인에 걸쳐 꽤나 합리적인 사이즈에 주석이 잘 달린 구현이 있다.

피드백은 환영하고 감사드린다.

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
  // The base Class implementation (does nothing)
  this.Class = function(){};

  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;

    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;

    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;

            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];

            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);
            this._super = tmp;

            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }

    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }

    // Populate our constructed prototype object
    Class.prototype = prototype;

    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;

    return Class;
  };
})();

두개의 교묘한 부분에 대한 내 의견은 “초기화/init을 호출하지 않고“,

_super 메서드를 생성“하는 부분이다.

난 저 부분에 대해 간단히 다루길 원했고, 그래서 이 메서드를 구현하는 것에

대한 잘 이해할 수 있을 것이다.

–  초기화 – 

function prototype과 함께 상속을 모의시험하기 위해 우리는 super-class의

객체를 생성하는 전통적인 기술을 사용했고 그것에 prototype을 할당했다.

그것을 이와 같이 사용할 수 있을 것이다.(?)

function Person(){}
function Ninja(){}
Ninja.prototype = new Person();
// Allows for instanceof to work:
(new Ninja()) instanceof Person

이것에 대한 도전은, Person객체를 설명하는 전체 비용 없이 ‘instanceof’의 이익이

우리가 정말로 원하는 모든 것이다. 우리 코드안의 변수에 대응하기 위해,

initializing(초기화), prototype을 위해 그것을 사용하는 단 하나의 목적과 함께

우리가 클래스  상속을 할때는 언제든지 그것은 맞는 조합이다.

그래서 함수를 정말로 만들 시점에, 우리는 초기화 메서드가 필요하지 않고

정확히는 init method를 실행한다.

if ( !initializing )
  this.init.apply(this, arguments);

이것에 관해 특별히 중요한 것은 init method가 비용이 많이 드는 시작코드의 모든 종류를

실행할 수 있다(서버 연결, DOM 요소 만들기) 그래서 일하는 데 처해지는 어려움을 제법 잘

피하게 된 것이다.

-슈퍼 메서드-

당신이 상속을 할때, 슈퍼 클래스로부터 기능을 상속하는 클래스를 만드는 것은,

자주 쓰이는 것은 당신이 오버라이드 한 메서드에 접근하는 능력이다.

마지막 결과로, 이 특별한 구현안에, 서브 클래스의 메서드 안으로부터

오직 접근가능한, 슈퍼 클래스와 연결된 메서드를 참조하는 새로운

임시 메서드(_super)가 있다.

예를 들면, 슈퍼 클래스의 생성자를 호출하길 원한 경우 이런 기술을

사용할 수 있다.

var Person = Class.extend({
  init: function(isDancing){
    this.dancing = isDancing;
  }
});
var Ninja = Person.extend({
  init: function(){
    this._super( false );
  }
});

var p = new Person(true);
p.dancing; // => true

var n = new Ninja();
n.dancing; // => false

이 기능의 구현은 몇가지 스텝이 있다. 시작을 위해, 우리가 이미 존재하는 클래스를

확장해 사용하는(Person.extend와 같은), 새로운 Person 객체의 기초위에 합쳐져야

할 필요하기 있는(이전에 기술된 구조 위에) 객체 리터럴에 주목하라.

우리는 간단한 체크를 한다 : 우리가 기능을 합치는 시도, 그리고 또한 기능을

대체하는 것에 대한 소유가 있는가? 우리는 새로운 슈퍼 메서드가 하는 일을

위한 방법을 만드는 것이 필요하다.

새로운 강화된 슈퍼 메서드를 압축하게 될 익명의 종결(함수가 리턴되는) 을

만든다.  To start we need to be ad good citizen(?), 기존의 this._super에 참조를

저장한다(실제 존재하는 걸 무시하고) 그것은 우리가 한 이후에 회복한다.

이것은 같은 이름이 이미 존재하는(사고로 그것을 떠나보내길 원하지 않는)

변수가 있는 곳에 대한 경우에 도움을 줄 것이다.

다음으로 우리는 슈퍼클래스의 prototype에 존재하는 메서드의 참조를 가진

새로운 _super메서드를 만든다. 고맙게도 우리는 어떤 부가적인 변화를

만들지 않아도 된다. 여기 함수의 문맥처럼 우리 객체(이것은 슈퍼클래스에

반대는 객체를 참조할 것이다)의 소유를 자동으로 조합할 것이다.

마침내 우리는 우리의 원래 메서드를 호출한다. 그것은 자신의 역할을 수행한다

후에 우리는 그것의 원래 상태에 _super를 회복하고 함수로부터 리턴받는다.

지금 간단한 결과를 구현한 대한 다양한 방법이 있다.

(인자들로부터 접근가능하고, 그 자신의 메서드에 슈퍼 메서드의 경계를 가지는

구현을 본) 그러나 난 유용함과 간단함의 최고 조합을 이 기술이 제공했으리라

느낀다.

난 나의 완벽한 일 안에 자바스크립트 prototype system뒤에 nitty-gritty의 많은

것이 담겨져 있을 것이다.

하지만  난 이 클래스 구현으로 부터 그것을 시도하고 구현함에 있어 모든 것을

얻기를 바란다. 나는 이 간단한 코드(배우기 쉽고, 확장하기 쉽고, 다운로드에

부담이 없는)에 많은 것을 말할 수 있으리라 생각한다.

그래서 난 이 구현이 좋은 출발점이 되리라 생각하고 자바스크립트 클래스 구조와

상속의 기본을 배울 수 있다.

Advertisements

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

w

%s에 연결하는 중