Skip to content

Instantly share code, notes, and snippets.

@Leko
Last active December 24, 2015 21:09
Show Gist options
  • Save Leko/6863603 to your computer and use it in GitHub Desktop.
Save Leko/6863603 to your computer and use it in GitHub Desktop.
所謂クラスパターンをいちいち書くのが面倒で、特に継承周りなんてバグバグでいちいち書いてられないので、extendでコンストラクタ関数を拡張できるようにしました。 定数の宣言など、ある程度自分の好みに寄せた作りをしています。 ライブラリとしてではなく、このコードをコピペ、改変して直接組み込むという感じを想定しています
// 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