JavaScriptの継承イディオム coffeescriptとtypescriptの比較
coffeescriptのclass syntaxで生成されたコードと、typescriptのそれは、お互いに継承でき、互換があると言われている。
本当に互換があるのかちゃんと調べないといけないなーと常々思ってたので、確認する。
検証コード
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 した結果を個のプロトタイプとして格納する。
使う側
継承箇所以外は割愛。
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使って良い。
たぶんどっかで名前が付いてるパターンなんだろうけど、調べるのめんどい。