1

好的,所以我们试图让原型继承按照我们想要的方式工作,我已经阅读了一些示例,但我们想要的一个要求是我们可以轻松地调用父类上的方法。我们希望遵循模块模式+ jQuery 样板样式,我们有默认值、非空构造函数和原型函数

;(function($, window, undefined){

    "use_strict";

    var defaultsHuman = {

        id: 1,

        age: 0
    };

    function Human( options ){

        this.options = $.extend(defaultsHuman, options || {});

        this.age = this.options.age;
        this.gender = 'male';

        //save originals for ref
        this._defaults = defaultsHuman;

    };
    Human.prototype = {

        _className: 'Human',

        init: function(){

            console.log('My class is ' + this._className + ' my gender is ' + this.gender + ' and my age is ' + this.age);

        }

    };

    //Right now Human's function prototype's constructor is Object(), but IE8 uses constructor.prototype
    //well now it's Object which is native so it's undefined?, anyways we lose the original reference to the constructor from the instance
    //so lets reset it to the constructor - constructor is now enumerable!

    Human.prototype.constructor = Human; //note this is cyclical!

    //END fn Human


    var defaultsChild = {

        name: ''

    };

    //we want to create a new constructor B that has properties, its constructor prototype is an instance of Human
    function Child( options ){

        //merge the parent defaults with my defaults, then extend dynamic options on top
        this.options = $.extend(this.constructor.prototype._defaults, defaultsChild, options || {});

        this.name = options.name;

        //A.call(this);

    };
    //new Human() calls Human's constructor and returns an object with prototype set to Human.prototype
    Child.prototype = new Human();

    $.extend(Child.prototype, {

        school: 'St. Peter\'s',

        init: function(){

            //create reference to super class
            this._super = this.constructor.prototype;

            //this._super.init.call(this);
            this._super.init();

            console.log('My name is ' + this.name + ' and my school is ' + this.school); 
        }

    });
        Child.prototype.constructor = Human;
    //END Child


    //export modules - old method before define
    window.Human = Human;
    window.Child = Child;

})(jQuery, window, undefined);



//some other closure somewhere where it is required in
;(function(window, undefined, Human, Child){

    "use_strict";

    var me = new Child({
        name: 'Clarence',
        age: 7
    }).init();


})(window, undefined, Human, Child);

让我感到困惑的是,在Human's init函数中this引用了一个Human实例,但处于一种Human constructor从未运行过的状态,因此静态设置为男性的性别甚至不存在。

My class is Human my gender is undefined and my age is undefined 
My name is Clarence and my school is St. Peter's 

我可以通过调用来轻松解决这个问题this._super.init.call(this);,我可能会这样做,但我仍然很好奇。

在构造函数运行后,我将 Child的函数原型显式设置为完整的 Human 对象: Child.prototype = new Human();当我检查 child 的最终实例时me,原型是 Human,构造函数已经运行(如预期的那样),但在Human init变量内部this是这样的人类构造函数从未运行过。

当我引用我的超级时:this._super = this.constructor.prototype;这不是对此处声明的原型的引用Child.prototype = new Human();吗?当我打电话时this.super.init(),它不是在返回的上下文中运行new Human()吗?


另请注意,我避免使用proto以与 IE8 兼容

4

1 回答 1

1

不确定我是否理解正确,但您可以执行以下操作:

function Human( options ){

    this.options = $.extend(defaultsHuman, options || {});

    this.age = this.options.age;
    this.gender = 'male';

    console.log("whaat",this.age);

    //save originals for ref
    this._defaults = defaultsHuman;

};
function Child( options ){
    Human.call(this, options);
};
Child.prototype = Object.create(Human.prototype);
function Human( options ){

    this.options = $.extend(defaultsHuman, options || {});

    this.age = this.options.age;
    this.gender = 'male';

    //save originals for ref
    this._defaults = defaultsHuman;

};

如果您想支持 IE 8 及更低版本或没有 Object.create 的旧版浏览器,您可以使用polyfil或查看此答案,该答案具有用于与构造函数继承的辅助函数。

如果我调用 Human.prototype.init ,则没有this. This将指向Human.prototype相反。

  this.constructor === Human;
  this._super === this.constructor.prototype === Human.prototype;
  this._super.init === Human.prototype.init;

如果你想在 Child.prototype 上使用默认的 Human 值,那么你应该知道 Hukman 是为 Child 的所有实例共享的。如果你想调用 init ,你可以这样做:

    Child.prototype = Object.create(Human.prototype);
    Child.prototype.humanInstance = new Human();

    //... in the Child constructor body:
    this.humanInstance.init();
于 2013-08-23T03:10:51.733 回答