I am trying to understand inheritance in javascript
function baseClass(name) {
this.name = name;
this.getName = function() {
return this.name;
}
}
function subClass(id, company){
baseClass.call(this);
this.id = id;
this.company = company;
this.toString = function() {
return name + "\n" + this.id + "\n" + this.company;
}
}
subClass.prototype = Object.create(baseClass);
var s = new subClass();
s.toString(); //here the name property from the baseClass is not displayed.
How do correctly implement inheritance (classical / prototypical)
First, there are two minor issues:
Casing matters in JavaScript. Object.create needs to be lowercased, and your function names don't match (subClass vs SubClass). Usually, constructor function names are uppercased.
Use the property this.name (which is inherited) instead of the variable name (which is undefined) - see Javascript: Do I need to put this.var for every variable in an object?
How do correctly implement inheritance
Move the methods (which don't need to privileged, there are no local variables in the constructor scope) on the prototype objects. And let SubClass.prototype inherit from BaseClass.prototype, not from the BaseClass function.
function BaseClass(name) {
this.name = name;
}
BaseClass.prototype.getName = function() {
return this.name;
};
function SubClass(id, company){
BaseClass.call(this);
this.id = id;
this.company = company;
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.toString = function() {
return this.name + "\n" + this.id + "\n" + this.company;
};
new SubClass().toString() does not display the name property from the baseClass
You're calling the constructor without any arguments. The id, company and name properties will have the undefined value. Also, your SubClass doesn't even have a parameter for the name, and it doesn't pass anything to the BaseClass constructor invocation.
Related
I can create a Cat object and set a method on it's prototype to print out the cat's name.
var log = function(message) {
var results = $('#result');
results.append('<p>' + message + '</p>');
};
function Cat(name) {
this.name = name;
}
Cat.prototype.speak = function() {
log('My name is ' + this.name);
};
var fluffy = new Cat('Fluffy');
var tiddles = new Cat('Tiddles');
log(fluffy.name);
fluffy.speak();
log(tiddles.name);
tiddles.speak();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"></div>
However, when I try to set the cat's prototype to an animal, I can't access the speak method:
function Animal(name, sound) {
this.name = name;
this.sound = sound;
this.speak = function() {
log(sound + '! My name is ' + name);
};
}
function Cat(name) {
this.prototype = new Animal(name, 'Meow');
}
var fluffy = new Cat('Fluffy');
fluffy.speak(); // TypeError: undefined is not a function
Why does fluffy not get the speak() method of its prototype?
If you want to learn how to do inheritance in JS, please read this guide . prototype is a property of the constructor function, not the instance.
Why does fluffy not get the speak() method of its prototype?
Because it's not on its prototype. You are never mutating Cat.prototype. The way you set up Animal, you would have to call Animal inside Cat instead:
function Cat(name) {
Animal.call(this, name, 'Meow');
}
But if you want proper prototype inheritance, define speak on Animal.prototype and set up inheritance via Object.create:
function Animal(name, sound) {
this.name = name;
this.sound = sound;
}
Animal.prototype.speak = function() {
log(this.sound + '! My name is ' + this.name);
};
function Cat(name) {
Animal.call(this, name, 'Meow');
}
Cat.prototype = Object.create(Animal.prototype);
The problem is that you set speak as a privileged method inside Animal constructor.
However, that constructor is never called for Cat instances.
Moreover, you can't use prototype property to modify internal [[prototipe]] and change the object from which properties should be inherited. You can use non standard __proto__ or ECMAScript6 Object.setProtetipeOf, but better don't do that.
Instead, better use this approach:
function SuperClass(args) {
// Here add SuperClass privileged properties
}
// Here add public properties to SuperClass.prototype
function SubClass(otherArgs) {
// Add SuperClass privileged properties to SubClass instances:
SuperClass.call(this, args);
// Here add SubClass privileged properties
}
// Make SubClass instances inherit from SuperClass.prototype:
SubClass.prototype = Object.create(SuperClass.prototype);
// Fix constructor property, overriden in the line above
SubClass.prototype.constructor = SubClass;
// Here add public properties to SubClass.prototype
function log(message) {
document.body.innerHTML += '<p>' + message + '</p>';
}
function Animal(name, sound) {
this.name = name;
this.sound = sound;
}
Animal.prototype.speak = function() {
log(this.sound + '! My name is ' + this.name);
};
function Cat(name) {
Animal.call(this, name, 'Meow');
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
var fluffy = new Cat('Fluffy');
fluffy.speak();
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)
OK, I've revised most of the techniques to implement inheritance in JavaScript OOP.
As a Java programmer, I'm interested in the classical approach but here's the problem; say I want to create the Animal class (I know it's not a real class, but let me use this term) like this:
function Animal(name){
this.name = name;
}
Animal.prototype.getName = function() {
return this.name;
}
It is important to note that this is a concrete class in my first intention, I want to instantiate it, not just use it as a superclass. I may create several Animal instances, each one with its own name.
A possible way to extend this class is to do the following:
function Cat(name, owner) {
this.name = name;
this.owner = owner;
}
// ALTERNATIVE 1:
Cat.prototype = Object.create(Animal.prototype);
// ALTERNATIVE 2:
Cat.prototype = new Animal('LOLA');
// END OF ALTERNATIVES
Cat.constructor.prototype = Cat;
Cat.prototype.jump = function() {
alert(this.name + " jumping");
}
With the ALTERNATIVE 1 we just inherit the methods of the superclass, in fact we need to redefine the name property in the Cat. With the ALTERNATIVE 2 nothing actually changes, we just have one more object in the chain that holds a name property that's quite useless: it's the same for all the Cat instances.
The point here is that I've written the Animal class with its own name and I just throw it away as soon as I extend it. What I'd like to have though is a way to inherit both properties and methods and, most of all, I'd like to be able to reuse the Animal constructor.
The traditional way to inherit the properties of the base constructor is as follows:
function Cat(name, owner) {
Animal.call(this, name); // call the base constructor
this.owner = owner;
}
Cat.prototype = new Animal;
Cat.prototype.constructor = Cat;
Cat.prototype.jump = function () {
alert(this.name + " jumping");
};
The above code is equivalent to the following class in other languages:
class Cat extends Animal {
constructor(name, owner) {
super(name);
this.owner = owner;
}
jump() {
alert(this.name + " jumping");
}
}
The new way to inherit properties is exactly the same, save that we replace new Animal with Object.create(Animal.prototype). The reason we prefer the new way is because:
Calling new Animal is unnecessary overhead. The Cat constructor calls it again anyway.
Calling new Animal might not return a blank object. It might add some properties to the object.
We don't know what arguments to call new Animal with yet. Hence it makes no sense to call it.
Thus the preferred way of inheritance is now:
function Cat(name, owner) {
Animal.call(this, name); // call the base constructor
this.owner = owner;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.jump = function () {
alert(this.name + " jumping");
};
Note that it's important to call the base constructor because it may do some initialization which is necessary for the instance to work properly.
If you're interested in writing JavaScript code in a classical style then take a look at the following answer which describes prototype-class isomorphism. The following code it taken from the above answer:
function CLASS(prototype, base) {
switch (typeof base) {
case "function": base = base.prototype;
case "object": prototype = Object.create(base, descriptorOf(prototype));
}
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
function descriptorOf(object) {
return Object.keys(object).reduce(function (descriptor, key) {
descriptor[key] = Object.getOwnPropertyDescriptor(object, key);
return descriptor;
}, {});
}
Using the CLASS function we can define pseudo-classes in JavaScript as follows:
var Animal = CLASS({
constructor: function (name) {
this.name = name;
},
getName: function () {
return this.name;
}
});
var Cat = CLASS({
constructor: function (name, owner) {
Animal.call(this, name);
this.owner = owner;
},
jump: function () {
alert(this.name + " jumping");
}
}, Animal);
There are other ways to do inheritance in JavaScript as well. I suggest you read my blog post on Why Prototypal Inheritance Matters to understand more about inheritance in JavaScript.
I had written this code to simulate OOP inheritance and calling baseclass in javascript and it works:
function Animal(name,age)
{
this._name = name;
this.setName = function (name) { this._name = name }
this.getName = function() { return this._name }
}
function Cat(name,age)
{
Animal.call(this,name,age); // call baseclass constructor
this.getName = function() { return Cat.prototype.getName.call(this)+", a cat" }
}
Cat.prototype = new Animal(); // will create the baseclass structure
/// ***** actual execution *****
var puss = new Cat("Puss",3);
var cheshire = new Cat("Cheshire",10);
// do some actions
console.log ( puss.getName() );
// change cat's name
puss.setName("Puss in boots");
alert ( "new name -->"+puss.getName() );
problem is that, for each instance of "new Cat()" the "getName" and "setName" functions are replicated.
I have read a lot of articles on prototyping but none addressed the issue of calling the baseclass function.
You should assign the methods to the prototype of the function, for example,
function Animal(name, age) {
this._name = name;
this._age = age;
}
Animal.prototype.getName = function () { return this._name; }
Animal.prototype.setName = function (value) { this._name = value; }
function Cat(name, age) {
Animal.call(this, name, age);
}
Cat.prototype = new Animal();
Cat.prototype.getName = function () {
return Animal.prototype.getName.call(this) + ", a cat";
}
Are you looking for __proto__ which stores prototype data?
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/Proto
If you do a console.log(puss.__proto__.getName) you'll get what seems to be the "baseclass" function but I'm not sure how cross-browser is this.
From http://phrogz.net/js/classes/OOPinJS2.html
Javascript does not have any sort of 'super' property, which would
point to its parent class. Instead, you use the call() method of a
Function object, which allows you to run a function using a different
object as context for it. If you needed to pass parameters to this
function, they would go after the 'this'.
In your case it works the same for functions as "methods", so you can do:
Animal.prototype.setName.call(this, name);
I have the following javascript
function person() {
//private Variable
var fName = null;
var lName = null;
// assign value to private variable
fName = "Dave";
lName = "Smith";
};
person.prototype.fullName = function () {
return this.fName + " " + this.lName;
};
var myPerson = new person();
alert(myPerson.fullName());
I am trying to get an understanding of object orientated techniques in javascript. I have a simple person object and added a function to its prototype.
I was expecting the alert to have "Dave Smith", however I got "underfined underfined". why is that and how do I fix it?
Unfortunately you can't access a private variable. So either you change it to a public property or you add getter/setter methods.
function person() {
//private Variable
var fName = null;
var lName = null;
// assign value to private variable
fName = "Dave";
lName = "Smith";
this.setFName = function(value){ fName = value; };
this.getFName = function(){ return fName; }
};
see javascript - accessing private member variables from prototype-defined functions
But actually this looks like what you are looking for:
Javascript private member on prototype
from that SO post:
As JavaScript is lexically scoped, you can simulate this on a per-object level by using the constructor function as a closure over your 'private members' and defining your methods in the constructor, but this won't work for methods defined in the constructor's prototype property.
in your case:
var Person = (function() {
var store = {}, guid = 0;
function Person () {
this.__guid = ++guid;
store[guid] = {
fName: "Dave",
lName: "Smith"
};
}
Person.prototype.fullName = function() {
var privates = store[this.__guid];
return privates.fName + " " + privates.lName;
};
Person.prototype.destroy = function() {
delete store[this.__guid];
};
return Person;
})();
var myPerson = new Person();
alert(myPerson.fullName());
// in the end, destroy the instance to avoid a memory leak
myPerson.destroy();
Check out the live demo at http://jsfiddle.net/roberkules/xurHU/
When you call person as a constructor, a new object is created as if by new Object() and assigned to its this keyword. It is that object that will be returned by default from the constructor.
So if you want your instance to have properties, you need to add them to that object:
function Person() {
// assign to public properties
this.fName = "Dave";
this.lName = "Smith";
};
Incidentally, by convention functions that are intended to be called as constructors are given a name starting with a capital letter.
You're declaring those variables as local to the function, instead of making them part of the object. In order to put them in the instance, you've got to use 'this' in the constructor as well. For example:
function person() {
this.fName = 'Dave';
this.lName = 'Smith';
}
person.prototype.fullName = function () {
return this.fName + " " + this.lName;
};
var myPerson = new person();
alert(myPerson.fullName());
In the constructor you should assign your variables to this:
this.fName = null;
this.lName = null;
But then they are not private. JavaScript does not have private variables like a "classic" Object Oriented language. The only "private" variables are local variables. An alternative to the above is to assign getter/setter methods to this within the constructor.