I am new at learning JavaScript concepts. Want to understand how prototypical inheritance work. My impression was if your class inherits its parent, and you have a same named method in prototypes of both classes, when you call the method on child instance, the method in the child prototype will be called.
Code:
function Animal(name) {
this.name = name;
}
Animal.prototype.printName = function () {
console.log(this.name + ' in animal prototype');
}
function Cat(name) {
Animal.call(this, name);
}
Cat.prototype.printName = function () {
console.log(this.name + ' in cat prototype');
}
Cat.prototype = Object.create(Animal.prototype);
var anm1 = new Animal('mr cupcake');
anm1.printName();
var cat1 = new Cat('cat');
cat1.printName();
On calling cat1.printName() I expected it to log 'cat in cat prototype' but it logged 'cat in Animal prototype'. Could someone please explain the reason to me. Thanks.
You are correct, but your override of the printName() function is, itself, being overridden by the next line when you reset the Cat.prototype. Simply moving the order of the code fixes the issue:
function Animal(name) {
this.name = name;
}
Animal.prototype.printName = function() {
console.log(this.name + ' in animal prototype');
}
function Cat(name) {
Animal.call(this, name);
}
// OLD LOCATION of code
// This was overriding your override!
// Setting the prototype of an object to another object
// is the basis for JavaScript's prototypical inhertiance
// This line replaces the existing prototype object (which is
// where your override was) with a completely new object.
Cat.prototype = Object.create(Animal.prototype);
// NEW LOCATION
// AFTER setting the prototype (and creating inheritance),
// it is safe to do the override:
Cat.prototype.printName = function() {
console.log(this.name + ' in cat prototype');
}
var anm1 = new Animal('mr cupcake');
anm1.printName(); // "mr cupcake in animal prototype"
var cat1 = new Cat('cat');
cat1.printName(); // "cat in cat prototype"
Related
I have the following simple inheritence pattern and I would like to know if it's ok to call methods the way i do from within the constructor function (basically speaking, using this instead of "super prototype".
Parent class, Pet
function Pet(name) {
this.name = name;
this.nickname = name;
this.adopt();
}
Pet.prototype.adopt = function() {
this.nickname = 'Cutty ' + this.name;
}
Pet.prototype.release = function() {
this.nickname = null;
}
Pet.prototype.cuddle = function() {
console.log(this.name + ' is happy');
}
Subclass, Lion
function Lion(name) {
Pet.prototype.constructor.apply(this, arguments); // super(name)
this.cuddle();
this.release();
}
Lion.inherits(Pet);
Lion.prototype.adopt = function() {
// DTTAH
}
Lion.prototype.release = function() {
Pet.prototype.release.call(this);
console.log('Thanks for releasing ' + this.name);
}
inherits helper (polyfills are bad I know)
Function.prototype.inherits = function(Parent) {
function ProtoCopy() {}
ProtoCopy.prototype = Parent.prototype;
this.prototype = new ProtoCopy();
this.prototype.constructor = this;
}
My pets are instantiated like so var lion = new Lion('Simba')
In Lion constructor,
Can I keep using this when calling sub/parent class methods ? Or should I use methods from parent prototype directly ? (like pseudo call to super() or in release())
Reasons why I am asking are:
this substitution at runtime
constructor property not always what we are thinking (from what I read here and there)
I am not sure how these things can influence the resulting object.
Thanks for your enlightenment !
What is the difference between using this.fn() and MyClass.prototype.fn.call(this) in a constructor function?
This is not specific to constructor functions, it's the same in all functions (methods) that are called on instances.
Indeed there's not much difference apart from the character count when this.fn === MyClass.prototype.fn, and they would behave exactly the same. However, this assumption is not always true - this might not inherit from MyClass.prototype directly, but rather be a subclass instance, and that subclass might have overwritten the this.fn method.
So which one is correct? Both, in fact. If you know the difference, you can choose the appropriate one for your case. Other languages have different default expectations here, see also for calling static methods.
Notice that you cannot replace the class reference by this.constructor, which would be overwritten as well. In a reasonable setup1, this.fn() would be always equivalent to this.constructor.prototype.fn.call(this).
This is similar to the reason why super calls must explicitly reference the super class, and not depend on instance properties (such as this.constructor, this.super or anything similar).
1: Where this.fn is a usual method inherited from the prototype, not an own instance-specific one, and where every prototype has the .constructor pointing to the respective constructor whose .prototype it is.
Simplifying the problem, consider the following code in ES6:
class Pet {
constructor (name) {
this.name = name;
this.talk();
}
talk () {
console.log('My name is ' + this.name);
}
}
class Lion extends Pet {
constructor (name) {
super(name);
}
talk () {
super.talk();
console.log('I am a lion.');
}
}
would be equivalent to:
function Pet (name) {
this.name = name;
this.talk();
}
Pet.prototype.talk = function () {
console.log('My name is ' + this.name);
};
function Lion (name) {
Pet.call(this, name);
}
// inheritance:
Lion.prototype = Object.create(Pet.prototype);
Lion.prototype.constructor = Lion;
// override .talk
Lion.prototype.talk = function () {
Pet.prototype.talk.call(this);
console.log('I am a lion');
}
Running new Lion('Bobby') logs:
My name is Bobby
I am a lion
Further reading: http://eli.thegreenplace.net/2013/10/22/classical-inheritance-in-javascript-es5
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();
I am trying to understand the prototype inheritance in Javascript. There have been several questions already asked on this, but they do not seem to address the confusion I am having.
How does JavaScript .prototype work?
What is the 'new' keyword in JavaScript?
There are also some great resources on the internet.
http://www.webdeveasy.com/javascript-prototype/
http://javascriptissexy.com/javascript-objects-in-detail/
When I read those resources, I think I understand prototypical inheritance, but when I try some tests in the browser console I realise I am missing something.
Based on the code example below:
(1) why is the added prototype function description() not visible on the parent object animal ?
(2) why is an object created after the description() function is added now missing the original object attributes: name and color?
Example:
Create a simple object.
function animal(){
var name;
var colour;
}
Create two new objects based on the prototype animal
> cat = new animal();
< animal {}
> cat.name = 'cat';
> cat.color = 'black';
> cat
< animal {name: "cat", color: "black"}
Add an attribute to one object only
> dog = new animal();
> dog.name = 'dog';
> dog.color = 'brown';
> dog.bite = 'hurts';
> dog
< animal {name: "dog", color: "brown", bite: "hurts"}
> animal.prototype.description = function(){
console.log('A ' + this.name + ' is ' + this.color); }
< function (){
console.log('A ' + this.name + ' is ' + this.color); }
Add a new function as a prototype. This all works as I expected it to.
> animal
< function animal(){
var name;
var colour;
}
> dog
< animal {name: "dog", color: "brown", bite: "hurts", description: function}
> cat
< animal {name: "cat", color: "black", description: function}
Here is the confusion. the new function description appears on both of the existing dog and cat objects, but it does not appear on the parent object animal
> cat.description;
< function (){
console.log('A ' + this.name + ' is ' + this.color); }
> cat.description();
< A cat is black
A new object cow created from the parent animal now has only the description function, but not the name or color
> cow = new animal();
< animal {description: function}
> cow
< animal {description: function}
EDIT
Based on #Quince's answer, I went back to the browser, but am still confused:
>animal = function(){
this.name;
}
<function (){
this.name;
}
>animal
<function (){
this.name;
}
>cat = new animal();
<animal {}
>cat
<animal {}
In this case the new object cat doesn't seem to inherit the name property from the parent.
in this example here
function animal(){
var name;
var colour;
}
name and colour are private to animal and as such can not be accessed.
now when you run this
cat = new animal();
< animal {}
> cat.name = 'cat';
> cat.color = 'black';
you are actually not setting those private name and colour attributes inside animal you are giving it new attributes called name and colour
when you run the following
animal.prototype.description = function(){
console.log('A ' + this.name + ' is ' + this.color);
}
animal is being given a publicly accessible function called description which is why you can see it when you create a cow, but actually this function will not print anything yet as the animal class does not have a name or color attribute.
options you have here are to change animal to
function animal(){
this.name;
this.colour;
}
although this gives no advantages other letting you know you can set this attributes of the animal, you will still need to set them in order for description to print anything.
Another option if wanting to keep things private and public is to use something along the lines of the revealing module pattern which allows js to keep attributes private to an object by declaring them outside of the object you return.
function Animal() {
//private artibutes
var name;
var colour;
//return publically avaliable functions/attibutes
return {
description: function () {
console.log('A ' + name + ' is ' + colour);
},
setName: function (nameIn) {
name = nameIn;
},
setColour: function (colourIn) {
colour = colourIn;
},
getName: function () {
return name;
},
getColour: function () {
return colour
}
}
};
now the only way to access the private name and color is to use the publicly available functions returned here is a fiddle showing it in action http://jsfiddle.net/leighking2/fxrLpj9v/
Oh and just realized i never actually answered the question in the title, so when you print animal you do not see the added description function as this function is attached to the prototype, animal when printed raw is just a constructor. Anything created using new Animal will inherit from animal's prototype which is why it can be seen in dog and cow
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.
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