クラス風継承を今どきの書き方でやってみる

More than 5 years have passed since last update.

発端は自分が書いたブログ記事に対して、@hokacchaさんが今風の書き方ってことでReplyしてくれたのがきっかけです。

ベースというか、ほぼそれのコピペですが記事元ではやっていない処理が追加されていたり、実装していないものがあったりしたのでそれを追加・修正したものです。

'use strict'しても動きます。(翻訳記事元arguments.callee使ってるので、strictモードで動きません)

(function (win, doc, exports, undefined) {

'use strict';

var fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

function Class() { /* noop. */ }

Class.extend = function (props) {

var SuperClass = this;

function Class() {
if (typeof this.init === 'function') {
this.init.apply(this, arguments);
}
}

Class.prototype = Object.create(SuperClass.prototype, {
constructor: {
value: Class,
writable: true,
configurable: true
}
});

Object.keys(props).forEach(function (key) {
var prop = props[key],
_super = SuperClass.prototype[key],
isMethodOverride = (typeof prop === 'function' && typeof _super === 'function' && fnTest.test(prop));

if (isMethodOverride) {
Class.prototype[key] = function () {
var ret,
tmp = this._super;

Object.defineProperty(this, '_super', {
value: _super,
configurable: true
});

ret = prop.apply(this, arguments);

Object.defineProperty(this, '_super', {
value: tmp,
configurable: true
});

return ret;
};
}
else {
Class.prototype[key] = prop;
}
});

Class.extend = SuperClass.extend;

return Class;
};

exports.Class = Class;
}(window, window.document, window));


使い方はこんな感じ。

(function (win, doc, exports, undefined) {

'use strict';

var Person = Class.extend({
init: function () {
console.log('hoge');
}
});

var Ninja = Person.extend({
init: function () {
this._super();
console.log('foo');
}
});

var Samurai = Ninja.extend({
init: function () {
this._super();
console.log('bar');
},
_super: 'super!'
});

var p = new Person();
var n = new Ninja();
var s = new Samurai();

console.log(s._super);

}(window, window.document, window));