Prototypal inheritance in JS and how to get parent properties - javascript

I'm trying to have properties inherit from a parent, but I'm not clear as to the right way of doing it.
Lets say I have:
var Animal = function(name){
this.offspring = [];
this.name = name;
return this;
}
Animal.prototype.createOffspring = function(name){
name = name || 'Baby '+(this.offspring.length+1);
this.offspring.push(name);
return this;
}
Now I want to add a sub prototype inherit so I don't have to manually add everything from the parent. For example, lets say I want to add a Cat based from Animal
I'd like to do this, like if it were an Animal
var pet = new Cat('Kitty');
pet.createOffspring();
Without manually having to add name and createOffspring to the Cat constructor which is really just an Animal, but with some other added functionality (like .meow() or something).

// Parent
function Animal() {
this.name = 'An animal';
}
// Some child
function Cat() {
this.speaks = 'Meow';
}
// Here comes inheritence
Cat.prototype = new Animal();
// Or like that
// but don't forget to put all inheritable fields to Animal's prototype
Cat.prototype = Object.create(Animal.prototype);
// Let 'instanceof' work. Don't forget the following line,
// because we eraese the info about constructor of Cat instances.
Cat.prototype.constructor = Cat;
// Add some custom method
Cat.prototype.meow = function() { return this.speaks; }
var cat = new Cat();
var animal = new Animal();
/// Some tests
cat.name; // A animal
animal.name; // An animal
cat.meow(); // Meow!
cat instanceof Cat; // true
cat instanceof Animal; // true
That's it?
(UPD: Error with prototype fixed)
(UPD2: Sorry. It is late night, I make a lot of mistakes.. I must go sleep)
There is also another solution, but its Chrome,FF-specific (maybe others):
// Animal and Cat functions from above, but
Cat.prototype = {
__proto__: Animal.prototype,
constructor: Cat,
meow: function() { ... }
}
Looks shorter, but not'd be tempted by this: it's better to follow ECMAScript standart.

There are a number of different patterns for implementing inheritance like you're describing in JavaScript, and they have subtle differences as far as how they treat the prototype objects.
Here's are a couple of good references on the prototype pattern and the constructor pattern to get you started.
And here's a simple implementation of what you described.

Related

javascript proto-chaining confusion on this

While going over below tutorial code
Animal = function(name) {this.name = name}
Animal.prototype.eats = function(){
return this.name + ' is eating'
}
Chordate = function(name){Animal.call(this,name)}
I understand how call works (basically, in this case, this becomes this)... but my question is, how does one use this?
I am sorry, I understand how prototype works.. But really, I don't understand once you setup Chordate as above.. how does one use it?
How is this useful? or How are you now suppose to specify the this?
Can someone please explain w/ example?
Create a link to Animal's prototype methods:
Chordate.prototype = Object.create(Animal.prototype)
Then new it up:
var c = new Chordate('my name');
c.eats();
The line Animal.call(this,name) is like making a call to a base constructor. It executes the Animal constructor function and passes in name, but uses the correct this context:
Animal = function(name) {
// "this" will be your Chordate instance
this.name = name
}
Lets imagine youre constructing an Animal:
new Animal();
and during construction it draws a new animal onto the canvas. The constructor would look like this:
function Animal(){
canvas.draw(this.x,this.y,this.image);
}
Now youve got a tiger. The tiger should roar if it is constructed.
function Tiger(){
this.roar();
}
And now? Its an animal so its added to the canvas right? No. Because of js inheritance system, you need to do this manually. So when the tiger gets constructed, you also need to construct it as an animal:
Animal.call(this);
This is even easier with the new class syntax:
class Animal{
constructor(){
this.draw(this.x,this.y,this.image);
}
}
class Tiger extends Animal{
constructor(){
this.roar();
super()//construct Animal
}
}
This is just meant to be an addition to the other answers, and would be too long for a comment.
Perhaps it helps you to understand what the new operator actually does:
var newInstance = new ConstructorFunction(arg1, arg2);
Create a new object. The prototype of this object is ConstructorFunction.prototype:
var newInstance = Object.create(ConstructorFunction.prototype);
Call the ConstructorFunction with the newly created object:
ConstructorFunction.call(newInstance, arg1, arg2);
If ConstructorFunction inherits from another "class", it has to call its super constructor. That's what the following code does:
function Parent () {
// this === newInstance
}
function Child () {
// this === newInstance
Parent.call(this); // call the super constructor
}
Child.prototype = Object.create(Parent.prototype);
var newInstance = new Child();
// or:
var newInstance = Object.create(Child.prototype);
Child.call(newInstance); // call the constructor, which calls the super constructor

How to inherit specific prototype method in JavaScript?

I tried to find the answer, but it's hard to find a good one.
Probably the problem is well-known, but please help me.
I cannot make this work:
function Animal() {}
function Cat() {}
Animal.prototype.walk = function() { return 'I can walk' }
Animal.prototype.swim = function() { return 'I can swim' }
If I write:
Cat.prototype = new Animal();
Cat inherits walk and swim method, so what should I write to make Cat inherit only walk method?
You could assign a prototype object (*.prototype) another Object Literal ({}) but be careful for inheritage does not work properly anymore:
function Person() {}
Person.prototype.walk = function() { return 'I can walk' }
Person.prototype.swim = function() { return 'I can swim' }
function Man() {}
// select methods Man gets inherited here
// just assign certain methods from Person.prototype onto Man.prototype
// therefore Man.prototype inherites only walk method
Man.prototype = {
walk: Person.prototype.walk,
// so swim is not passed onto Man.prototype
// swim: Person.prototype.swim
};
var m = new Man();
// this throws an error
// because a object of type Man does not have got a swim method inherited
// m.swim(); Error!
console.log('is false: ', m instanceof Person);
console.log('parent constructor is Object: ', m.__proto__.__proto__.constructor);
But as you can see some checks to make sure what instance this object is and what super parent constructor it inherits some methods from do not work properly but they should work.
So you are better off by using inheritage in the right way:
function Person() {}
Person.prototype.walk = function() { return 'I can walk' }
Person.prototype.swim = function() { return 'I can swim' }
function Man() {}
Man.prototype = Object.create(Person.prototype);
var m = new Man();
// in this way Person gets every method that is assigned onto Person.prototype
// so swim method is available and can be used by objects of type Man now:
m.swim();
console.log('is true: ', m instanceof Person);
console.log('parent constructor is Person: ', m.__proto__.__proto__.constructor);
So that like instanceof operator and referenceing to a super parent constructor work properly. In this way all methods are assigned at once onto Person but by introducing additional abstract or parent constructors this might be avoidable.
Hope this helps.
I think the main problem is not how to make that cat inherit walk and not swing: I think that is impossible in the way you show, but the issue here is a not complete understanding of the inheritance hierarchy.
Look, basically what are you saying is: A Cat is an Animal, so it doesn't make sense that he doesn't inherit ALL the Animal behavior. Because if you say: An Animal is defined as someone that can WALK and SWING, and then you say: A Cat is a type of Animal, then the Cat MUST WALK AND SWING.
I think in your case you need to reorganize the hierarchy. Maybe you can make a LandAnimal, and a WaterAnimal, and a Cat will be a LandAnimal, and a Fish will be a WaterAnimal. Now, if you add a Duck, well, again you have to redefine because a Duck is a WaterAnimal (he can SWING) AND a LandAnimal (he can WALK).

Javascript Prototypal inheritance with Multiple Objects

Say I have 5 Objects
Callback
Perishable
Object1
Object2
Object3
Object1 needs to extend the Callback but not the Perishable object, whereas Object 2 should extend both and Object 3 should extend Perishable but not callback.
I know this works...
Object1.prototype = new Callback();
Object3.prototype = new Perishable();
but how would I do something like (I know this isnt working)
Object2.prototype = new Callback() && new Perishable();
If you don't want any external dependencies, you can use this implementation of extend:
function __extends(d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
var a = function(){}; a.prototype = new b();
for (var p in a.prototype) d.prototype[p] = a.prototype[p];
};
Example:
var animal = function(){
};
animal.prototype.run = function(){
console.log("running");
};
var feline = function(){
};
feline.prototype.hunt = function(){
console.log("hunting");
};
var cat = function(){
};
__extends(cat, animal);
__extends(cat, feline);
var scaryCat = new cat();
scaryCat.run();
scaryCat.hunt();
Fiddle: http://jsfiddle.net/apqwf93a/9/
You can use extend function from Underscore.js library.
The code would look like this:
_.extend(Object1.prototype, Callback.prototype);
_.extend(Object1.prototype, Perishable.prototype);
Here's JS fiddle: http://jsfiddle.net/yb7kkh4e/2/
Usually when you want to extend multiple objects you have to look if your design is correct. Is the object the other object?
For example a Cat is an Animal and a Cat can move. To extend the Cat from Movable would be wrong because the Cat is not a Movable it can move so it should implement Movable or leave default implementation of Movable.
The example of Cat Feline and Animal is fine but could be solved without multiple inheritance. A Cat is a Feline and a Feline is an Animal so no reason for Cat to both inherit from Feline and Animal you could have Cat inherit from Feline and Feline from Animal.
The chosen answer deals with the prototype part of mix ins (implements) but doesn't cover how to initialize instance specific members. Here is the mix in part of the following answer that does:
Multiple inheritance with mix ins
Some things are better not to be inherited, if a Cat can move and than a Cat should not inherit from Movable. A Cat is not a Movable but rather a Cat can move. In a class based language Cat would have to implement Movable. In JavaScript we can define Movable and define implementation here, Cat can either override, extend it or us it's default implementation.
For Movable we have instance specific members (like location). And we have members that are not instance specific (like the function move()). Instance specific members will be set by calling mxIns (added by mixin helper function) when creating an instance. Prototype members will be copied one by one on Cat.prototype from Movable.prototype using the mixin helper function.
var Mixin = function Mixin(args){
var i, len;
if(this.mixIns){
i=-1;len=this.mixIns.length;
while(++i<len){
this.mixIns[i].call(this,args);
}
}
};
Mixin.mix = function(constructor, mix){
var thing
,cProto=constructor.prototype
,mProto=mix.prototype;
//no extending, if multiple prototype uhs
// have members with the same name then use
// the last
for(thing in mProto){
if(Object.hasOwnProperty.call(mProto, thing)){
cProto[thing]=mProto[thing];
}
}
//instance intialisers
cProto.mixIns = cProto.mixIns || [];
cProto.mixIns.push(mix);
};
var Movable = function(args){
args=args || {};
//demo how to set defaults with truthy
// not checking validaty
this.location=args.location;
this.isStuck = (args.isStuck===true);//defaults to false
this.canMove = (args.canMove!==false);//defaults to true
//speed defaults to 4
this.speed = (args.speed===0)?0:(args.speed || 4);
};
Movable.prototype.move=function(){
console.log('I am moving, default implementation.');
};
var Animal = function(args){
args = args || {};
this.name = args.name || "thing";
};
var Cat = function(args){
Animal.call(args);
//if an object can have others mixed in
// then this is needed to initialise
// instance members
Mixin.call(this,args);
};
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Mixin.mix(Cat,Movable);
var poochie = new Cat({
name:"poochie",
location: {x:0,y:22}
});
poochie.move();

Prototype instance like cat c = new animal();?

I am newbie to Javascript and recently, I faced this question and am curious to know the answer.
function animal(){
// some bse code
}
function cat(){
//some cat code
}
// I know this syntax and works well
cat.prototype= new animal;
and I would like to know the below syntax is correct?
cat c = new animal;
Is it possible in javascript?
(sorry! If the question exists.)
and I would like to know the below syntax is correct?
cat c = new animal;
No, JavaScript variables are always loosely typed, so you don't declare types for them, you just declare them with var (and in ES6, let).
So:
var c = new animal;
Side note #1: In JavaScript, the overwhelming convention is to use an initial capital letter for functions that are intended to be used as constructor functions (e.g., via the new keyword). E.g., Animal and Cat, not animal and cat.
Side note #2: About this:
// I know this syntax and works well
cat.prototype= new animal;
That's a common, but poor, practice. Here's how to do that correctly:
cat.prototype = Object.create(animal.prototype);
cat.prototype.constructor = cat;
...and then in cat, as the first thing:
animal.call(this);
Complete example with updated capitalization:
function Animal() {
}
function Cat() {
Animal.call(this);
// ...add Cat-level initialization here
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
About Object.create: It's an ES5 function that creates an object with a specific underlying prototype. The proper ES5 version takes two arguments, and what it does with the second argument cannot be shimmed on older browsers. But for what we're doing, we only need the first argument, which can be shimmed on older browsers:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw "Object.create shims cannot implement the second argument.";
}
function ctor() { }
ctor.prototype = proto;
return new ctor();
};
}
So why is Cat.prototype = new Animal; poor practice? Well, what if Animal takes per-instance arguments? Consider:
function Animal(age) {
this.age = age;
}
What would we give for age in the Cat.prototype = new Animal(???); line?
Answer: We don't. We shouldn't call Animal, which is a constructor function for instances, until we're constructing an instance. Instead, we create a new object for the Cat.prototype property, and give that new object Animal.prototype as its prototype.
Complete example:
function Animal(age) {
this.age = age;
}
function Cat(age, color) {
Animal.call(this, age);
this.color = color;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
var c = new Cat(14, "Tabby");
No, it is not. In JavaScript you can't declare the type of a variable. The type of a variable is the type of its current value, so
var c = new animal(); //correct
but
cat c = new animal(); //parse error.

Can a revealing prototype pattern extent another revealing prototype pattern

I'm trying to use the revealing prototype patter to extend a "class". As an example I have an Animal and a Fish.
Here's what I'd like to be able to to:
Fish to Inherit the prototype from Animal
Override members of Animal if needed
Add new members to the Fish prototype
Do all this while still using the revealing prototype pattern for both "classes"
I can create the Animal "class":
var Animal = function(data) {
this.name = ""
this.color = "";
this.weight = 0;
};
Animal.prototype = function() {
var eat = function() {
document.write(this.name + " is eating.<br>");
}
return {
constructor: Animal,
eat: eat
};
}();
And I can create a Fish "class" that inherits from Animal:
var Fish = function(data) {
this.isSwimming = false;
};
Fish.prototype = new Animal();
The prototype for the Fish is where I'm running into trouble. Is it possible to use the revealing prototype pattern for Fish and still inherit the prototype from Animal and override Animal if needed? (I'm not completely opposed to using a third party library to do this, but I'd prefer not to.) For example, how could I override eat() and add a new function to Fish called swim?
Edit:
Here's what I've come up with. This seems to do what I need. Am I missing anything?
Fish.prototype = new function(proto) {
var base = proto.constructor;
var eat = function(data) {
new base().eat (data);//This is just to show you can call the base. If needed.
document.write("fish eating.<br>");
};
var swim = function(){
document.write("fish is swimming.<br>");
};
var thisProto = {
constructor: Fish,
eat: eat,
swim: swim
};
for (var propt in thisProto) {
proto[propt] = thisProto[propt];
}
return proto;
}(new Animal());
Edit:
In the answer I accepted, one of the main points was to not use the new keyword. So I researched the difference between the new keyword and Object.create(). If I understand things correctly, they both do basically the same thing, but Object.create() will not call the objects constructor while the new keyword will. If you need to inherit something that is defined in the constructor, you'll need to use the new keyword or move that member to the prototype.
Here's a plunk that I used to experiment with this some more: http://plnkr.co/edit/322WB4jyCJberABbb0P0
Am I missing anything?
Yes.
new function(proto) {
Do not use new.
new base().eat (data);//This is just to show you can call the base. If needed.
Do not use new. You'd create a new instance here, however what you want is get the eat method from the base.prototype and call that on your Fish instance.
proto = new Animal()
Do not use new!
Fish.prototype = (function(super) {
var proto = Object.create(super);
function eat(data) {
super.eat.call(this, data);
document.write("fish eating.<br>");
}
function swim(){
document.write("fish is swimming.<br>");
}
proto.constructor = Fish;
proto.eat = eat;
proto.swim = swim;
return proto;
})(Animal.prototype);

Categories