Last active
December 24, 2015 21:09
-
-
Save Leko/6863603 to your computer and use it in GitHub Desktop.
所謂クラスパターンをいちいち書くのが面倒で、特に継承周りなんてバグバグでいちいち書いてられないので、extendでコンストラクタ関数を拡張できるようにしました。
定数の宣言など、ある程度自分の好みに寄せた作りをしています。
ライブラリとしてではなく、このコードをコピペ、改変して直接組み込むという感じを想定しています
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// extendでコンストラクタ定義してくパターン | |
var MyApp = {}; | |
MyApp.Core = (function() { | |
// 何かコアとなる処理・プロパティがあれば追加 | |
function Core() { | |
} | |
Core.prototype = { | |
}; | |
/** | |
* オブジェクトのコピーを行う | |
* 既にプロパティの定義されているオブジェクトに追加拡張を行いたい際にはtargetに渡す | |
* @private | |
* @method copy | |
* @param {Object} obj コピーしたいオブジェクト | |
* @param {Object} [target] オブジェクトをコピーする対象。省略した場合からのオブジェクトを使用する | |
* @return {Object} コピーしたオブジェクト | |
*/ | |
function copy(obj, target) { | |
var ret = target || {}; | |
for(var p in obj) { | |
if(!obj.hasOwnProperty(p)) continue; | |
if(typeof obj[p] === "object") { | |
ret[p] = copy(obj[p]); | |
} else { | |
ret[p] = obj[p]; | |
} | |
} | |
return ret; | |
} | |
/** | |
* コアモジュールの拡張を行う | |
* 親コンストラクタから子コンストラクタに継承されるものは、 | |
* 1. 静的メンバ・メソッド | |
* 2. インスタンスメソッド | |
* 3. メンバ変数 | |
* この際、参照ではなくコピーで継承を行うので、子に何か変更を及ぼしても親には干渉しない | |
* | |
* @static | |
* @method extend | |
* @param {Object} props 拡張するメソッドを渡す | |
* 【重要】 | |
* 1. `__construct`というキーに格納されたメソッドを、コンストラクタ関数と見なす | |
* 2. 関数以外の値を指定すると、子コンストラクタの静的メンバ(定数)と見なす | |
*/ | |
Core.extend = function(props) { | |
var Ctr = props.__construct; | |
Ctr.constructor = props.__construct; | |
// extendをコピー | |
Ctr.extend = this.extend; | |
// 親クラスのprototypeを継承 | |
Ctr.prototype = new this(); | |
// 関数以外のオブジェクトは静的メンバとしてコピーし削除(prototypeには入れない) | |
copy(this, Ctr); | |
for(var p in props) { | |
if(props.hasOwnProperty(p) && typeof props[p] !== "function") { | |
Ctr[p] = props[p]; | |
delete props[p]; | |
} | |
} | |
// 呼び出し元のプロトタイプを子にコピーする(親との参照を切る) | |
copy(props, Ctr.prototype); | |
return Ctr; | |
}; | |
return Core; | |
}()); | |
/** | |
* case1: コアを拡張 | |
*/ | |
MyApp.Human = MyApp.Core.extend({ | |
// NOTE: 関数以外の値は静的メンバに追加する(定数としての使用を想定) | |
SEX_MAN: 1, | |
SEX_WOMAN: 2, | |
// NOTE: コンストラクタ関数 | |
__construct: function Human(name, age, sex) { | |
this.name = name; | |
this.age = age; | |
this.sex = sex; | |
}, | |
// NOTE: __constructを除く全ての関数はprototypeに追加される | |
say: function() { | |
console.log("My name is", this.name, "and", this.age, "years old."); | |
}, | |
isMan: function() { | |
return this.sex === MyApp.Human.SEX_MAN; | |
}, | |
isWoman: function() { | |
return this.sex === MyApp.Human.SEX_WOMAN; | |
} | |
}); | |
/** | |
* case2: コアを拡張したHumanを拡張 | |
*/ | |
MyApp.Unisex = MyApp.Human.extend({ | |
SEX_UNISEX: 0, | |
__construct: function Man(name, age) { | |
this.name = name; | |
this.age = age; | |
this.sex = MyApp.Unisex.SEX_UNISEX; | |
}, | |
isUnisex: function() { | |
return this.sex === MyApp.Unisex.SEX_UNISEX; | |
} | |
}); | |
var leko = new MyApp.Human("Leko", 21, MyApp.Human.SEX_MAN); | |
leko.say(); // My name is Leko and 21 years old. | |
leko.isMan(); // true | |
leko.isWoman(); // false | |
leko.isUnisex; // undefined | |
var manwo = new MyApp.Unisex("Elisabeth", 12); | |
manwo.say(); // My name is Elisabeth and 12 years old. | |
manwo.isMan(); // false | |
manwo.isWoman(); // false | |
manwo.isUnisex(); // true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment