1

私のコードの一部がスタックオーバーフローを引き起こしている理由を理解するのに役立つことを望んでいました。

問題のコード:

var ClassCreator = {
    create: function(class_object,ParentClass){
        var created_class = null;


        created_class = function(){        
            if(arguments.length == 0){
                this.constructor();
            }else{
                this.constructor.apply(this,arguments);
            }        
        };

        this._grantInheritance(created_class,ParentClass);
        this._grantMethods(created_class,class_object);    

        return created_class;
    },

    _grantInheritance: function(created_class,ParentClass){
        if(ParentClass){
            created_class.prototype = ParentClass.prototype;
            created_class.prototype.BaseClass = ParentClass;
        }
    },

    _grantMethods: function(created_class,creation_object){
        //If there's no constructor provided, add a default constructor.
        if(!creation_object.constructor){
            creation_object.prototype.constructor = function(){};
        }

        //Add the creation_object's methods to the class we're creating.
        for(var property in creation_object){
            created_class.prototype[property] = creation_object[property];
        }
    }
};

var SuperSuperObject = ClassCreator.create({
    constructor: function(){
        document.write("Hello");
    }
});

var SuperObject = ClassCreator.create({
    constructor: function(){
        this.BaseClass.call(this);

        document.write(" ");
    }
},SuperSuperObject);

var RegularObject = ClassCreator.create({
    constructor: function(){
        this.BaseClass.call(this);

        document.write(" World");
    }
},SuperObject);

var test = new RegularObject();​

私が理解できる限り、RegularObjectsコンストラクターでthis.BaseClass.callを呼び出すと、RegularObjectsコンストラクターを再度呼び出そうとするため、スタックオーバーフローが発生します。SuperObjectのコンストラクターではなく、RegularObjectのコンストラクターを呼び出す理由はわかりません。何か案は?


編集:将来誰かがそれを望む場合に備えて、私の解決策:

var ClassCreator = {
    __PROTOTYPE_CONSTRUCTOR_SIGNAL__:  "1821fe18a870e71b29a6219e076b80bb",

    create: function(class_object,ParentClass){
        var created_class = null;


        created_class = function(){
            var call_class = null;


            if(arguments.length == 1){
                if(arguments[0] == ClassCreator.__PROTOTYPE_CONSTRUCTOR_SIGNAL__){
                    if(this.prototypeConstructor){
                        this.prototypeConstructor();
                    }

                    return;
                }
            }


            if(!this.__construct_stack){
                this.__construct_stack = 0;
            }
            call_class = this;
            for(var counter = 0;counter<this.__construct_stack;counter++){
                call_class = call_class.BaseClass.prototype;
            }
            this.__construct_stack++;


            if(arguments.length == 0){
                call_class.constructor.call(this);
            }else{
                call_class.constructor.apply(this,arguments);
            }


            return this;
        };


        this._grantInheritance(created_class,ParentClass);
        this._grantMethods(created_class,class_object); 

        return created_class;
    },

    _grantInheritance: function(created_class,ParentClass){
        if(ParentClass){
            created_class.prototype = new ParentClass(this.__PROTOTYPE_CONSTRUCTOR_SIGNAL__);
            created_class.prototype.BaseClass = ParentClass;
        }
    },

    _grantMethods: function(created_class,creation_object){
        //If there's no constructor provided, add a default constructor.
        if(!creation_object.constructor){
            creation_object.prototype.constructor = function(){};
        }

        //Add the creation_object's methods to the class we're creating.
        for(var property in creation_object){
            created_class.prototype[property] = creation_object[property];
        }
    }
};
4

1 に答える 1

1

問題

RegularObjectのコンストラクターでは、BaseClassメソッドのコンテキストをRegularObjectに設定しています。これで、SuperObjectのコンストラクターに入ると、「this」はRegularObject(先ほどのオブジェクトと同じオブジェクト)を参照し、RegularObjectのBaseClassメソッドを再度呼び出します(this.BaseClass.call(this);RegularObjectのコンストラクターと同じになります)。また、同じオブジェクトを使用してBaseClassを再度「呼び出す」ため、stackoverflow/無限ループが発生します。

最良の説明ではありませんが、おそらくいくつかの例が役立つでしょう...

これは、何が起こっているかを強調する簡略化されたコードブロックです

フィドル: http: //jsfiddle.net/GVkDv/1/

var base = function(){
    //"this" now references the object we just came from along with it's methods 
    //and properties. 
    this.BaseClass.call(this); 
}

base.prototype.BaseClass = function(){ alert('made it to the base'); }

var derived = function(){
    alert('About to stackoverflow'); 
    this.BaseClass.call(this);//"call" keeps the context to the object we're on 
}

derived.prototype = new base(); //construct base the first time. 1st Alert.
derived.prototype.BaseClass = base; 

var x = new derived(); ​

解決

これを修正するには、継承された基本クラスのインスタンスを参照するコンテキストオブジェクトを維持する必要があります。

例:

フィドル: http: //jsfiddle.net/bboone/GVkDv/6/

var superbase = function(){
    var ctx = this; //maintain context of the initialized prototype object

    this.init = function(){
        alert('superbase'); 
    };

    this.init(); 
}

var base = function(){
    var ctx = this; //maintain context of the initialized prototype object

    this.init = function(){
        //ctx and this are referencing different objects
        ctx.BaseClass.init.call(this); 
    };

    this.init(); 
}

base.prototype = new superbase(); //construct superbase the first time. 1st Alert.
base.prototype.BaseClass = base.prototype;    

var derived = function(){
    var ctx = this; 

    this.init = function(){
        //ctx and this are referencing different objects
        ctx.BaseClass.init.call(this); 
    };

    this.init(); 
}

derived.prototype = new base(); 
derived.prototype.BaseClass = derived.prototype; 

var x = new derived(); 
x.init(); //call all the way down the inheritance chain. 

十分に文書化された/精査された遺伝パターンがたくさんあることを指摘する必要があります。

いくつかの例:

于 2012-09-18T03:10:21.677 に答える