読者です 読者をやめる 読者になる 読者になる

JavaScriptの継承イディオム coffeescriptとtypescriptの比較

coffeescriptのclass syntaxで生成されたコードと、typescriptのそれは、お互いに継承でき、互換があると言われている。

本当に互換があるのかちゃんと調べないといけないなーと常々思ってたので、確認する。

検証コード

coffeescript

class A
  f: ->
    console.log 'super'

class B extends A
  f: ->
    super
    console.log 'sub'
b = new B
b.f()

typescript

class A{
    f() {
        console.log('super');
    }
}
class B extends A {
    f(){
        super.f();
        console.log('sub');
    }
}

var b = new B;
b.f()

やってることは全く一緒

ヘッダー

継承を行うとどちらもヘッダに継承用ユーティリティを出力する

coffeescript(ワンライナー化してあるのを展開してある)

var
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) {
  for (var key in parent) {
    if (__hasProp.call(parent, key)) child[key] = parent[key];
  }
  function ctor() { this.constructor = child; }
  ctor.prototype = parent.prototype;
  child.prototype = new ctor();
  child.__super__ = parent.prototype;
  return child;
}

typescript

var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};

使ってるプロパティ名にやや揺れがあるとは言え、やってることはほぼ同一と思って良い。 唯一の違いは、coffeeの方はchild.__super__ に継承元のprototypeの参照を保存してるぐらいか。

constructorとしてスーパークラスの関数を代入した空の関数を生成し、そのプロトタイプを new した結果を個のプロトタイプとして格納する。

使う側

継承箇所以外は割愛。

coffeescript

B = (function(_super) {
  __extends(B, _super);

  function B() {
    return B.__super__.constructor.apply(this, arguments);
  }

  B.prototype.f = function() {
    B.__super__.f.apply(this, arguments);
    return console.log('sub');
  };

typescript

var B = (function (_super) {
    __extends(B, _super);
    function B() {
        _super.apply(this, arguments);
    }
    B.prototype.f = function () {
        _super.prototype.f.call(this);
        console.log('sub');
    };
    return B;
})(A);

このとき、coffeeの方のサブクラス B.__super__.constructor === _super.prototype => true なので、結果として同じ。

この時、お互いに継承したときに注意するべき点があるとすれば、coffeeの作ったサブクラスの__super__を触らないことぐらいだと思う。普通触らないと思うので安心して一つのプロジェクトで複数altjs使って良い。

たぶんどっかで名前が付いてるパターンなんだろうけど、調べるのめんどい。