JSシミュレーションクラス継承

4010 ワード

//最後のパラメータはJSONが示すクラス定義
//パラメータが1より大きい場合、最初のパラメータはベースクラスであり、そうでない場合、ベースクラスはobjectである
//中間のパラメータはクラス実装のインタフェース
//戻り値はクラス、クラスは構造関数であり、ベースクラスのprototypeを継承します.


    
function Class(){
        aDefine = arguments[arguments.length - 1];//入力された最後のパラメータは定義するクラスです
        if(!aDefine) return;//パスパラメータを使用しない場合は、そのまま終了します.
        var aBase = arguments.length>1?arguments[0]:object;//伝達されるパラメータが1より大きい場合、最初のパラメータはベースクラスであり、1に等しい場合、ベースクラスのデフォルトはobjectである
        function prototype_(){};//プロトタイプチェーンを接続するprototype一時関数の作成
        prototype_.prototype = aBase.prototype;
        var aPrototype = new prototype_();//クラスで使用するプロトタイプオブジェクトの作成
        for(var member in aDefine){
if(aDefine[member]!='Create'){//コンストラクション関数はプロトタイプチェーンに掛けなくても、コンストラクション関数は最終的に返されます.
                aPrototype[member] = aDefine[member];
            }
        }
//クラスの設定
if(aDefine.Create){//コンストラクション関数がある場合
            var aType = aDefine.Create;//クラスはこのコンストラクタです
}else{//コンストラクション関数がなければ
var aType=function(){//デフォルトのコンストラクタの作成
                this.base.apply(this, arguments);//親クラスのコンストラクション関数を呼び出す
            }
        }
        aType.prototype = aPrototype;//クラス(コンストラクション関数)のプロトタイプの設定
        aType.Base = aBase;//タイプ関係の設定
        aType.prototype.Type = aType;//オブジェクトのタイプを判断するために、このクラスのオブジェクトにType属性を拡張します.
        return aType;//プロトタイプ継承を加えたコンストラクション関数を返すとnewになります
    }
    function object(){};//最も基本的な方法と属性を実現するためにobjectルートクラスを定義します.
    object.prototype.isA=function(type){//オブジェクト属性が何らかのタイプに属しているか否かを判断
        var self = this.Type;
        while(self){
            if(self == type){
                return true;
            }
            self = self.Base;
        }
        return false;
    }
    object.prototype.ベースクラスのコンストラクタを呼び出す
        var Caller = object.prototype.base.caller;//この関数を呼び出す関数を取得
        Caller && Caller.Base && Caller.Base.apply(this, arguments);
//Callerが存在しCaller.ベースが存在する場合はCallerを呼び出す.ベースメソッド
//若果CallerまたはCaller.ベースには存在しない文があるので、後の文は実行しなくてもいいです.
    }
var people=Class({//peopleクラスの定義
        Create: function(name, age){
            this.base();
            this.name = name;
            this.age = age;
        },
        say: function(){
            console.log('My name is ' + this.name + ",I'm "+ this.age + '.');
        }
    })
    var chinaPeople = Class(people,
        {
            Create: function(name, age, country){
                this.base(name, age);
                this.country = country;
            },
            sayCountry: function(){
                console.log('My country is ' + this.country);
            }
        }
    )
    var man1 = new people('kaka', 32);
    var man2 = new chinaPeople('kaka', 32, 'china');
    man2.say();  //My name is kaka,I'm 32.
    man2.sayCountry();  //My country is china 
callerはoperaブラウザをサポートしていないのでbaseメソッドを書き換える
  object.prototype.base = function(){
        var Base = this.Type.Base;//現在のオブジェクトのベースクラスの取得
if(!Base.Base){//ベースクラスがない場合
            Base.apply(this, arguments);//ベースクラスコンストラクタを直接呼び出す
        }else{
            this.base = MakeBase(Base);//まずこれを複写します.base
            Base.apply(this, arguments);
            delete this.base;//複写baseプロパティの削除
        };
        function MakeBase(Type){
            var Base = Type.Base;
if(!Type.Base)return Base//ベースクラスにベースクラスがないので、包装する必要はありません
return function(){//一時変数Baseを参照する閉パッケージ関数としてパッケージ
                this.base = MakeBase(Base);//まずこれを複写します.base
                Base.apply(this, arguments);//ベースクラスコンストラクタを呼び出す
            }
        }
    }