2010/05/13
JS is OOP : 継承順序を意識しない class と extends
JavaScript には include や import がなく、かわりに html のヘッダーにファイルの数だけタグをぽちぽち書きます。
クラスでファイル分けすると量が半端ないので、手作業より自動化ツールを作ったほうが早いというもんですが、自動化するとクラス継承にまつわる読み込み順序がネックになってきます。
クラス継承順を整理して考えるより、js上でクラス継承キューを作った方が早いです。
用例
$class('ThumbQueueView',$extends('View',{
draw:function(){
$('Body').innerHTML = '<div id="ThumbQueueAsExternal"></div>';
this.drawSWF({
name :'img/swf/ThumbQueue.swf?'+time(),
id :'ThumbQueueAsExternal',
width :'100%',
height :'100%',
vars :{}
});
}
}));
//↓継承する View クラスが後に来てても通る
$class('View',{
draw:function(){},
drawSWF:function(swf){
swfobject.embedSWF(
swf.name, swf.id, swf.width,swf.height,
'9.0.0', 'img/swf/expressInstall.swf',swf.vars,
{allowFullScreen:'true',allowScriptAccess:'always'},
{id:swf.id,align:'middle'}
);
}
}
var view = new ThumbQueueView();
view.draw();
ソース
//要 prototype.js
var $classes = {};
var $classQueue = {};
function forEach(obj,func){
if(Object.isArray(obj)) {
for(var i=0;i<obj.length;i++) {
if (obj[i]) {
func(i, obj[i])
}
}
}else {
for(var key in obj){
func(key,obj[key])
}
}
}
function $class(name,obj){
if(Object.isArray(obj)){
if(!(obj[0] in $classQueue)) $classQueue[obj[0]] = [];
$classQueue[obj[0]].push({
className:name,
superClassName:obj[0],
contents:obj[1]
});
}else{
var c = ('isSubclassOf' in obj)?obj:$extends(null,obj);
c.className = name;
$classes[name] = c;
window[name] = c;
if (name in $classQueue) {
forEach($classQueue[name], function(i, value){
if (value.className) {
$class(value.className, $extends(value.superClassName, value.contents))
}
});
delete ($classQueue[name]);
}
}
}
function $extends(parentClass,classMethods){
var superClassEnable = true;
if(Object.isString(parentClass)){
if(parentClass in window){
var superClass = window[parentClass];
}else{
superClassEnable = false;
}
}else{
superClass = parentClass
}
if(superClassEnable){
var c = Class.create();
if(superClass) Object.extend(c.prototype, superClass.prototype);
Object.extend(c.prototype, classMethods);
c.superClass = superClass;
c.isSubclassOf = function(object){
if(!this.superClass) return false;
if(this.superClass == object) return true;
return this.superClass.isSubclassOf(object)
}
c.prototype.self = c;
return c;
}else{
return $A(arguments);
}
}