Ok so we're trying to get prototype inheritance working the way we want it to, I've read a few examples, but one requirement we wanted was that we could call methods on the parent class easily. And we want to follow the module pattern + jQuery boilerplate style where we have defaults, a non-empty constructor function and prototype functions
;(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);
What is confusing me is that in Human's init
function the this
refers to a Human
instance, but in a state as if the Human constructor
never ran, so gender which is statically set to male isn't even there.
My class is Human my gender is undefined and my age is undefined
My name is Clarence and my school is St. Peter's
I can easily fix this by calling this._super.init.call(this);
instead, which I'll probably just do, but I am still curious.
I explicitly set the function prototype of Child to a complete Human object after the constructor had run: Child.prototype = new Human();
when I inspect the final instance of child me
the prototype is Human where the constructor had run (as expected), but inside the Human init
the this
variable is such that the Human constructor had never run.
When I reference my super: this._super = this.constructor.prototype;
is this not a reference to the prototype declared here Child.prototype = new Human();
? And when I call this.super.init()
is it not running in the context of what was returned by new Human()
?
Also please note I am avoiding proto for compatibility with IE8
Not sure if I understand this correctly but you can do the following:
If you want to support IE 8 and below or older browsers that don't have Object.create you can use the polyfil or check out this answer that has a helper function for inheritance with constructor functions.
If I call Human.prototype.init there is no instance value for
this
.This
will point toHuman.prototype
instead.If you want to use a default Human value on the Child.prototype than you should know that Hukman is shared for all instances of Child. If you then want to call the init on that you can do so like this: