I'm attempting to learn Javascript inheritance and I've read some resources
Benefits of using `Object.create` for inheritance
How to "properly" create a custom object in JavaScript?
on Stack Overflow about inheriting objects in Javascript to get started.
My goal is hiding private members from outside and I tought that the Closure way of inheriting and creating objects, even if it is not very memory friendly, might help me so I came up with this code:
"use strict";
//State is 'saved' by the closure capturing the value
var Contact = function(address)
{
this.setAddressTo = function(newAddress)
{
address = newAddress;
};
this.getAddress = function()
{
return address;
}
};
var Person = function(name, surname, address)
{
//Superclass 'constructor' which will inherit everything public
Contact.call(this, address);
//Subclass members
this.getName = function()
{
return name;
};
this.setName = function(newName)
{
name = newName;
};
this.getSurname = function()
{
return surname;
};
this.setName = function(newSurname)
{
surname = newSurname;
};
//Also with the prototype chaining I can access superclass methods
this.setAddressTo = function(newAddress)
{
console.log('Setting address from base class');
Person.prototype.setAddressTo(newAddress);
}
}
Person.prototype = Object.create(Contact.prototype);
var p1 = new Person('#1.Name', '#1.Surname', '#1.Address');
var p2 = new Person('#2.Name', '#2.Surname', '#2.Address');
console.log('P1 is a person ? ' + (p1 instanceof Person)); //Yes
console.log('P1 is a contact ? ' + (p1 instanceof Contact)); //Yes
console.log('P2 is a person ? ' + (p2 instanceof Person)); //Yes
console.log('P2 is a contact ? ' + (p2 instanceof Contact)); //Yes
console.log(p1.getAddress()); //'#1.Address'
console.log(p2.getAddress()); //'#1.Address'
p1.setAddressTo('#1.Other_Address');
p2.setAddressTo('#2.Other_Address');
console.log(p1.getAddress()); //'#1.Other_Address'
console.log(p2.getAddress()); //'#2.Other_Address'
//Should be undefined because it is not accesible
console.log(p1.address);
console.log(p2.address);
The line:
Person.prototype = Object.create(Contact.prototype);
I use it for making the 'instanceof' operator working correctly (which means that a Person object is an instance of Person and Contact)
Is it correct to do this ?
These lines:
var p1 = new Person('#1.Name', '#1.Surname', '#1.Address');
var p2 = new Person('#2.Name', '#2.Surname', '#2.Address');
Is correct calling the function Person() with 'new' ?
To me it makes sense because I will receive a new Object with its prototype set to Person.prototype which has its prototype set to Contact.prototype (I guess) and this will make the newly created object effectively a Person.
The approach that I've posted is valid to achieve inheritance correctly in Javascript or other better best practices exists to achieve the same thing ?
Related
function Person() {}
Person.prototype.getFullName = function(){
var name = "John Micheal";
}
var p1 = new Person();
console.log(p1.getFullName());
Here I want to access the variable "name" to my other prototypes. Is this possible?
If not, Is there any other way to do ?
http://jsfiddle.net/KabeerRifaye/bcxqx1wj/
Thanks in advance.
You should probably go do some JavaScript tutorials. I recommend TreeHouse or CodeSchool.
Anyways, there are a few possible options / interpretations of your question.
If you're just trying to get the return value you need to use the return keyword. Now your console.log will output the name.
function Person() {}
Person.prototype.getFullName = function(){
var name = "John Micheal";
return name;
}
var p1 = new Person();
console.log(p1.getFullName());
If you truly want to share the value between functions you need to use the this keyword. In this example you can set the value in setName and retrieve it with getName.
function Person() {}
Person.prototype.getName = function(){
return this.name
}
Person.prototype.setName = function(newName) {
this.name = newName
}
var p1 = new Person();
p1.setName('John');
console.log(p1.getName());
These are hard concepts to learn on your own. I really recommend working through some JavaScript tutorials to learn this fundamental concepts.
I updated your version => http://jsfiddle.net/bcxqx1wj/3/
I would highly recommend to use a more generic get function:
Person.prototype.getData = function(prop){
if (this[prop] !== undefined) {
return this[prop];
} else {
return false;
}
}
Set function would look like this:
Person.prototype.setData = function(prop, data){
this[prop] = data;
}
Usual way to implement inheritance in javascript is something like:
function Person(name, surname) {
this.name = name;
this.surname = surname;
}
Person.prototype.whoAmI = function() {
console.log("I'am " + this.name + " " + this.surname);
}
function Ninja() {
Person.apply(this, arguments); // call to parent constructor
}
Ninja.prototype = new Person();
Ninja.prototype.constructor = Ninja;
var ninja = new Ninja("John", "Doe");
ninja.whoAmI();
From backbone what i can see is use of "Surrogate" function like: (very simplified example of what i can extract like example from Backbone source code)
function Person(name, surname) {
this.name = name;
this.surname = surname;
}
Person.prototype.whoAmI = function() {
console.log("I'am " + this.name + " " + this.surname);
}
function Ninja() {
Person.apply(this, arguments);
}
var Surrogate = function() { this.constructor = Ninja; }
Surrogate.prototype = Person.prototype;
Ninja.prototype = new Surrogate();
var ninja = new Ninja("John", "Doe");
ninja.whoAmI();
From what i can understand, these examples work exactly same so why need for Surrogate function.
I find one comment in the source about this:
Set the prototype chain to inherit from parent, without calling
parent's constructor function.
Why not calling parent constructor function?
Why not calling parent constructor function?
Because we want to constructor function to be only called when an instance is created. The Ninja.prototype however is not an instance of Person, it should not have name or surname properties - it should only inherit the whoAmI method. See also What is the reason to use the 'new' keyword at Derived.prototype = new Base for details.
Usual way to implement inheritance in javascript is something like
Only "something like". The correct way is not to call the parent constructor, but we don't need that Surrogate thingy for that. The standard is just to use Object.create:
Ninja.prototype = Object.create(Person.prototype);
Ninja.prototype.constructor = Ninja;
(for compatibility with ES3 environments just shim Object.create instead of littering your source code with Surrogate functions)
I am struggling to understand the constructor invocation pattern in Javascript.
I have a base object Mammal ( would it be incorrect to use the term class ? ) and an inherited object Cat. In the following code the object Cat correctly inherits from the Mammal object.
/*
Mammal base Object
*/
var Mammal = function(name) {
this.name = name;
}
Mammal.prototype.get_name = function() {
return this.name;
}
Mammal.prototype.says = function () {
return this.saying || '';
}
/*
Cat object
*/
var Cat = function (name) {
this.saying = "Meow";
this.name = name;
}
Cat.prototype.purr = function (number) {
var i =0, s='';
for ( i=0; i<number; i++)
if (s)
s +='-';
s+='r';
return s;
}
Cat.prototype = new Mammal();
console.log("Pseudo classical inheritance approach");
var mammal = new Mammal(" I am a mammal");
console.log("Who are you ? " + mammal.get_name());
console.log("What are you saying? " + mammal.says());
var cat = new Cat('I am a cat');
console.log("Who are you ? " + cat.get_name());
console.log("What are you saying? " + cat.says());
What I don't like in this pattern is how the constructor of the base object is used. The object Cat does not reuse correctly the constructor of the base class Mammal. I would like to have a more flexibility. Each time a Cat object is created, the constructor of the Mammal object is invoked with no arguments. I would like to use a mechanism similar to the "super" keyword in Java, so that when the constructor of Cat is called with name as parameter, also the constructor of Mammal is called with name as parameter.
I tried to implement the Cat constructor as follows :
var Cat = function (name) {
this.saying = "Meow";
// Super (name);
this.prototype = new Mammal(name);
}
This does not work as expected. this.prototype is undefined. why? Why this approach is completely wrong? does this point to the newly Cat object?
I know, there are different ways to implement inheritance in javaScript, but I am wondering if there is a way to implement the super mechanism like in Java.
Thanks. :D
How about
var Cat = function (name) {
this.saying = "Meow";
// Super (name);
Mammal.call( this, name );
}
Yes, I'm afraid that's not how you set up hierarchies. It's close, but there are a couple of key issues. (One of which — calling new Mammal() to create Cat.prototype — is a very, very, very frequent error you see in a lot of blog posts and such.)
Here's a simple example of doing it correctly:
// A function to set up the link between a child and parent
function derive(Child, Parent) {
// `ctor` is a temporary function we use so we can get an object
// backed by `Parent.prototype` but without calling `Parent`.
function ctor() { }
// Borrow the prototype
ctor.prototype = Parent.prototype;
// Create an object backed by `Parent.prototype` and use it as
// `Child`'s prototype
Child.prototype = new ctor();
// Some housekeeping to make the prototype look like the ones
// the JavaScript engine creates normally.
Child.prototype.constructor = Child;
// Note: If we can rely on ES5 features, we could use
// `Object.create` instead of the `ctor` function.
}
// The parent constructor
var Mammal = function(name) {
this.name = name;
};
// Some stuff for its prototype
Mammal.prototype.get_name = function() {
return this.name;
};
Mammal.prototype.says = function () {
return this.saying || '';
};
// The child constructor
var Cat = function(name) {
Mammal.call(this, name);
this.saying = "Meow";
};
// Hook it up to the parent
derive(Cat, Mammal);
// Add some things to its prototype
Cat.prototype.purr = function (number) {
var i =0, s='';
for ( i=0; i<number; i++)
if (s)
s +='-';
s+='r';
return s;
};
If you're interested in doing inheritance hierarchies in JavaScript, you may find my Lineage script useful. You may or may not choose to use it, but it demonstrates how to set things up, a way to do calls to the parent's version of methods ("supercalls"), etc. In particular, this documentation page comparing using Lineage to not using it shows how to do this without any helper script. But there's a reason I wrote a helper script to do it. :-)
this.prototype is undefined, because no one defined it.
Cat is a function. As such, it has a property prototype. That's mandated by the ECMAScript standard.
this is an object that is not a function. As such, the ECMAScript standard does not mandate that it has a prototype property.
If this is a Cat (i.e. an object that was or is created using new Cat), then it has, for the sake of specification, an internal [[Prototype]] property which is a Mamal. But this mamal is not accessible directly (as implied by the word internal). When you say var maru = new Cat(), then maru.[[Prototype]] is linked to Cat.prototype. That's how maru knows about future methods of mamals.
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:
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;
};
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 to Human.prototype instead.
this.constructor === Human;
this._super === this.constructor.prototype === Human.prototype;
this._super.init === Human.prototype.init;
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:
Child.prototype = Object.create(Human.prototype);
Child.prototype.humanInstance = new Human();
//... in the Child constructor body:
this.humanInstance.init();
What is wrong with this code? Can somebody help me with JavaScript Object Inheritance? I am starting to feel like an idiot!!
Thanks in advance,
Sam
function Human(name, sex) {
this.name = name;
this.sex = sex;
};
function Man(name) {
Man.prototype = new Human(name, "Male");
};
var m = new Man("Sam Striano");
alert(m.name); //<-- = Undefined
You want this instead:
function Man(name) {
Human.call(this, name, "Male");
}
What that code does
It seems like you're only trying to call the constructor of the parent, Human, which isn't the same is prototypal inheritance. The code above takes the constructor for Human and applies it to this - a new Man object.
What your code does
The line Man.prototype = new Human(name, "Male") is changing the prototype of Man every time a new Man is created. Not only that, you're completing re-assigning the prototype object, and so it will only apply to objects created after that assignment - i.e. not the first one. Hence, m.name is undefined.
Proper prototypal inheritance
Note that calling the parent's constructor, as in my code above, won't cause Man to automatically inherit any methods assigned to Human.prototype. The best way to do this is to clone Human.prototype into Man.prototype but outside of any constructors. Like this:
function Man(name) {
Human.call(this, name, "Male");
}
function inherit(parent, child) {
if (Object.create) child.prototype = Object.create(parent.prototype);
else {
for (var key in parent.prototype) {
if (!parent.prototype.hasOwnProperty(key)) continue;
child.prototype[key] = parent.prototype[key];
}
}
}
inherit(Human, Man);
This may seem rather verbose, and the alternative may be to do this:
Man.prototype = new Human('no name', 'Male');
Which will work, but causes unwanted side-effects since we're forced to assign a dud name to the prototype, and it's letting the constructor for Human call an extra time just for assigning the prototype. Be warned if you go down this path and later change the Human constructor to do more than just assign properties to this.
There's usually two steps to mimic classical inheritance in javascript:
Your subclass constructor needs to call the parent constructor
Your subclass prototype needs to chain into the parent prototype
the first step usually looks like
function Subclass(blah) {
ParentClass.apply(this, arguments);
}
The second step is trickier. On JS environments that implement the __proto__ property, you could do
Subclass.prototype = {
__proto__ : ParentClass.prototype,
subclassMethod1: function() { /* ... */ }
}
Unless you know exactly where your script will run (like in a node.js environment), you can't rely on __proto__ being available to your script, so the general approach will require to use Crockford's object() method:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
Subclass.prototype = Object.create(ParentClass.prototype);
Subclass.prototype.subclassMethod1 = function() { /* ... */ }
That's the gist of it. ES5 runtimes may have Object.create() already built-in, and that's fine.
There are leftover things to complete the illusion of classic inheritance, such as the ability to easily call a parent class' overriden method. With what we have now, you'd need to have something like ParentClass.prototype.overridenMethod.call(this, arg1, arg2) in your Subclass method.
Some OO libraries will helpfully define extra cruft on each of your subclass instances so you can use things like this.superclass.overridenMethod(arg1, arg2).
The implementation of that cruft is left as an exercise to the reader ;)
I think what you're after is to have the Man class in inherit properties from Human. You're on the right track, but would need to apply a new Human instance once as the prototype object of Man.
function Human(name, sex) {
this.name = "some default";
this.sex = sex;
};
function Man(name) {
if( name !== undefined )
this.name = name;
};
Man.prototype = new Human(name, "Male");
Man.prototype.constructor = Man;
var m = new Man("Sam Striano");
alert(m.name); // alerts "Sam Striano"
alert(m.sex); // alerts "Male"
As far as I know, you should handle all stuff with prototype and constructor and the inerithance could be managed in this way:
// Define superclass
function Human( name, sex ) {
this.name = name;
this.sex = sex;
}
// Define superclass methods
Human.prototype.method1 = function() {
alert( 'This is the call to ORIGINAL method1() with name: ' + this.name + ' and sex: ' + this.sex );
}
// Define subclass
function Man( name, age ) {
this.constructor.apply( this, [ name, 'Man' ] );
this.age = age;
}
// Define subclass inerithance
Man.prototype = new Human();
// Define subclass methods
Man.prototype.method1 = function() {
alert( 'This is the call to OVERWRITE method1() with name: ' + this.name + ' and sex: ' + this.sex + ' and age: ' + this.age );
this.constructor.prototype.method1.apply( this );
}
var m = new Man( 'Sam Satriano', 30 );
m.method1();
// Should alert:
// This is the call to OVERWRITE method1() with name: Sam Satriano and sex: Man and age: 30
// This is the call to ORIGINAL method1() with name: Sam Satriano and sex: Man
Hope this helps. Ciao!
Without getting into an inheritance fight, your problem can be solved by changing your code to the following:
function Human(name, sex) {
this.name = name;
this.sex = sex;
};
function Man(name) {
// This is how you call the parent's constructor
Human.call(this, name, "Male");
};
// The call to setup the prototype only needs to happen once
// Not in every instantiation of the object
Man.prototype = new Human();
// Have to fix the constructor, right now it's set to Human
Man.prototype.constructor = Man;
var m = new Man("Sam Striano");
>> m.name // outputs "Sam Striano";
>> m instanceof Human // outputs true
This is still not an ideal way to inherit. I posted something explaining what makes good JS inheritance. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html