Javascript Prototypal inheritance with Multiple Objects - javascript

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();

Related

Is it possible to using Javascript prototypes without using the "new" keyword?

The fact that Javascript uses functions to create objects was confusing to me at first. An example like this is often used to highlight how prototypes work in Javascript:
function Car(){
this.setModel=function(model){
this.model=model;
}
this.getModel=function(){
return this.model;
}
}
function Bus(){}
Bus.prototype=new Car();
var obj=new Bus();
obj.setModel('A Bus');
alert(obj.getModel('A Bus');
Is it possible to use prototypes without using new FunctionName()? I.e. something like this:
var Car={
setModel:function(model){
this.model=model;
},
getModel:function(){
return this.model
}
}
var Bus={
prototype:Car;
};
var obj=Bus;
obj.setModel('A Bus');
alert(obj.getModel());
This does not use functions and new to create objects. Rather, it creates objects directly.
Is this possible without deprecated features like Object.__proto__ or experimental functions like Object.setPrototypeOf()?
Object.create gets you the behavior that you are looking for, but you have to call it instead of new:
// Using ES6 style methods here
// These translate directly to
// name: function name(params) { /* implementation here */ }
var Car = {
setModel(model) {
this.model = model;
},
getModel() {
return this.model
}
};
var Bus = Object.create(Car);
var obj = Object.create(Bus);
obj.setModel('A Bus');
alert(obj.getModel());
Alternatively, you can use the new ES 2015's __proto__ property to set the prototype at declaration time:
var Bus = {
__proto__: Car
};
// You still need Object.create here since Bus is not a constructor
var obj = Object.create(Bus);
obj.setModel('A Bus');
alert(obj.getModel());
Some additional notes
You should add the methods to Car.prototype not inside of the constructor unless you need the private state (this way there is only one instance of the setModel method, rather than one instance of the method per instance of the class):
function Car() {}
Car.prototype.setModel = function(model) { this.model = model; };
Car.prototype.getModel = function(model) { return this.model; };
You can get around the new Car oddness with Object.create even with constructor functions:
function Bus {}
Bus.prototype = Object.create(Car);
Crockford has quite a good chapter on this subject in The Good Parts.
In it he points out one big flaw with using new on constructor functions:
Even worse, there is a serious hazard with the use of constructor functions. If you forget to use the new prefix when calling a constructor function, then this will not be bound to a new object... There is no compile warning, and there is no runtime warning.
(You may already be aware of this, hence your question, but it's worth reiterating)
His proposed solution is to recommend a home rolled Object.create (The Good Parts predates ES5 by a bit, but the idea is the same as the native version mentioned in the other answers).
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () { };
F.prototype = o;
return new F();
};
}
Object.create takes an instance of an object to use as the prototype and returns an instance.
The example used is very similar to your "something like this" example (except Crocky uses mammals and cats instead of cars and buses):
var car = {
setModel:function(model){
this.model=model;
},
getModel:function(){
return this.model
}
};
var bus = Object.create(car);
bus.setModel('A Bus');
alert(bus.getModel());
You can use Object.create() to achieve. Here is a crude example of prototypal inheritance using this :
// Car constructor
var Car = function() {};
Car.prototype = {
setModel: function(){},
getModel: function(){}
};
// Bus constructor
var Bus = function() {
Car.call(this); // call the parent ctor
};
Bus.prototype = Object.create(Car.prototype); // inherit from Car
var my_bus = new Bus(); // create a new instance of Bus
console.log(my_bus.getModel());
Prototypes allow you to make new object instances from other object instances. The new instance stands on its own and can be changed however you like.
var bus = Object.clone(Car.prototype);
bus.number = '3345';
bus.route = 'Chicago West Loop';
bus.setModel('A bus');
To use an instance as prototype in order to inherit shows a lack of understanding what prototype is. Prototype shares members and a mutable instance member of Parent on the prototype of Child gets you very unexpected behavior. Setting Car.prototype to Object.create(Bus.prototype) has already covered by others, if you want to see the role of the constructor and the role of the prototype maybe the following answer can help: https://stackoverflow.com/a/16063711/1641941
To demonstrate what could go wrong let's introduce an instance specific mutable member called passengers we would like Bus to initialize this so we can't use Jeff's example as that only takes care of the prototype part. Let's use constructor functions but create an instance of Bus for Car.prototype.
var Bus = function Bus(){
this.passengers=[];
}
var Car = function Car(){};
Car.prototype = new Bus()
var car1=new Car();
var car2=new Car();
car1.passengers.push('Jerry');
console.log(car2.passengers);//=['Jerry']
//Yes, Jerry is a passenger of every car you created
//and are going to create
This error could be resolved by shadowing instance properties by re using Parent constructor (Bus.call(this... as provided later) but Car.prototype still has a passengers member that has no business being there.
If you want to protect agains people forgetting "new" you can do the following:
function Car(){
if(this.constructor!==Car){
return new Car();
}
//re use parent constructor
Bus.call(this);
}
//Example of factory funcion
Car.create=function(arg){
//depending on arg return a Car
return new Car();
};
Car.prototype = Object.create(Bus.prototype);
Car.prototype.constructor = Car;
var car1 = Car();//works
var car2 = new Car();//works
var car3 = Car.create();//works
One approach - create a Car and use Object.create to make a copy and then extend Bus functionality as needed
(function () {
"use strict";
var setModel = function (model) {
this.model = model;
};
var getModel = function () {
return this.model;
};
var iAmBus = function () {
alert("only a bus!");
};
var Car = {
setModel: setModel,
getModel: getModel
};
var Bus = Object.create(Car);
// own bus property, not in the car
Bus.iAmBus = iAmBus;
var bus = Object.create(Bus);
bus.setModel('A Bus');
alert(bus.getModel());
var car = Object.create(Car);
car.setModel('A Car');
alert(car.getModel());
//inspect bus and car objects, proving the different object structure
console.log(bus);
console.log(car);
console.log(Bus);
console.log(Car);
}());

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);

When to use the word "prototype" in adding new properties to an object in javascript?

I don't understand in JavaScript when to use the word "prototype" vs. using simple "dot" notation without the word "prototype". Can someone look at these code blocks and help me understand when you'd want to use one over the other?
with "prototype":
function employee(name,jobtitle)
{
this.name=name;
this.jobtitle=jobtitle;
}
var fred=new employee("Fred Flintstone","Caveman");
employee.prototype.salary=null;
fred.salary=20000;
console.log(fred.salary);
without "prototype":
function employee(name,jobtitle,salary)
{
this.name=name;
this.jobtitle=jobtitle;
this.salary=salary;
}
var fred=new employee("Fred Flintstone","Caveman", 20000);
console.log(fred.salary);
JavaScript objects have a property which is a pointer to another object. This pointer is the object's prototype. Object instances by default share the same prototype:
function Employee(name){
this.name = name;
}
Employee.prototype.company = "IBM";
Employee.prototype.who = function(){
console.log("My name is", this.name, "I work for", this.company);
}
var bob = new Employee('Bob');
var jim = new Employee('Jim');
// bob and jim are seperate objects, but each is linked to the same 'prototype' object.
jim.who(); // jim doesn't have a property called 'who', so it falls back to it's 'prototype', where who exists
// My name is Jim I work for IBM
bob.who();
// My name is Bob I work for IBM
// Bob leaves IBM for Microsoft
bob.company = "Microsoft"; // bob now has a property called 'company'. The value of which is 'Microsoft', which overrides bob's prototype property of the same name.
bob.who();
// My name is Bob I work for Microsoft
Employee.prototype.company = 'Facebook';
jim.who();
// My name is Jim I work for Facebook
bob.who(); // Bob is not affected by the change.
// My name is Bob I work for Microsoft
delete bob.company;
bob.who(); // bob no longer has it's own property 'company', so like jim, it drops down to the prototype object.
// My name is Bob I work for Facebook
The issues around JS and inheritance may be complex, but the answer to your question is relatively simple. Consider this code:
function Klass() { }
var obj1 = new Klass();
var obj2 = new Klass();
Now, if you add a property to obj1, that property exists only on obj1. Likewise obj2.
If you add a property to Klass, that property likewise exists only on Klass (the function object). It doesn't affect obj1 and obj2 at all.
But if you add a property to Klass.prototype, that property will then be present on both obj1 and obj2, as well as any future objects created via new Klass. If you then change the value of the property on the prototype, the changed value will be what you see on all those objects.
You could add code inside the body of the Klass function to add properties to this; that will then cause any future Klass objects to get those properties. But each object would have its own copy - which can add up, memory-wise, especially when the properties are methods -and those copies would not be affected by future changes to the body of Klass.
ES5's Object.create almost removes the need to hassle around with .prototype anymore.
So, to pick up #Gerry's example, you can go like
var Mammal = {
walk: function() {}
};
var Dog = Object.create(Mammal, {
bark: {
value: function() {}
}
}); // create a new object which [[prototype]] refers to Mammal
Dog.walk();
Dog.bark();
The prototype object is a little tricky to understand; however this article on OOP JavaScript can help shed some light.
In a nutshell, the prototype object provides a blueprint for a 'recipient' object - all you have to do is point the recipient's prototype property at your blueprint object. Note that you can have as many recipients of a prototype blueprint object as you like (so Car and Train can both point to a common Vehicle prototype object).
You are free to define both properties and functions in a prototype object which will any recipient objects will be able to use, eg:
var vehiclePrototype = {
// A property which will be supplied to the recipient
cost: 0,
// A method which will be supplied the recipient
move: function () {
// Your prototype can refer to 'this' still.
console.log("Moving " + this.name);
};
}
You can now create a Car which makes use of the vechiclePrototype:
// Factory method for creating new car instances.
function createCar(name) {
// Define the Car's constructor function
function Car(name) {
this.name = name;
}
// Point the car's prototype at the vechiclePrototype object
Car.prototype = vechiclePrototype;
// Return a new Car instance
return new Car(name);
}
// Create a car instance and make use of the Prototype's methods and properties
var mustang = createCar(mustang);
mustang.cost = 5000;
mustang.move();
A new Train object could be created in a similar fashion:
function createTrain(whilstleSound) {
// Define the Train's constructor function
function Train(name) {
this.whilstleSound = whilstleSound;
}
// Point the train's prototype at the vechiclePrototype object
Train.prototype = vechiclePrototype;
// Return a new Train instance
return new Train(name);
}
var ic125 = new Train("pooop pooop");
ic125.move();
One of the big advantages of using Prototypical inheritance all instances of both Car and Train share the exact same move function (instead of creating multiple instances of the same function) which results in a significant memory saving if there are many instances of these objects.
Ignore new, ignore .prototype they are just confusing notions. If you really want prototypical inheritance use Object.create but most of the time inheritance is completely overkill. (prototypical inheritance should only be used as an optimization technique).
When building classes just create objects and extend them.
var Walker = {
walk: function() {}
}
var Eater = {
eat: function () {}
}
var Dog = extend({}, Eater, Walker, {
bark: function () {},
sniffBehind: function () {}
})
function dog(dogName) {
return extend({}, Dog, {
name: dogName
})
}
var steveTheDog = dog("steve")
console.log(steveTheDog.name === "steve")
Use any arbitrary arity extend function you want, _.extend, jQuery.extend, pd.extend, etc.
pd implements extend as follows
function extend(target) {
[].slice.call(arguments, 1).forEach(function(source) {
Object.getOwnPropertyNames(source).forEach(function (name) {
target[name] = source[name]
})
})
return target
}
With prototype, you can extend in a 'cleaner' way, because you are separating the logic inside your constructor function from the properties and methods that define your object.
var Mammal = function() { ... };
Mammal.prototype = {
walk: function() { ... }
};
var Dog = function() { ... };
for (var prop in Mammal.prototype) {
Dog.prototype[prop] = Mammal.prototype[prop];
}
Dog.prototype.bark = function() { ... };
However, the above without prototype could look like this:
var Mammal = function() {
this.walk = function() { ... };
};
var Dog = function() {
Mammal.apply(this);
this.bark = function() { ... };
};
This way of extending Objects is however made irrelevant by modern JavaScript libraries like Underscore.js, or could be written much cleaner with the help of for example jQuery too.
You could use the word prototype to define some functionality across the application for particular type (Array, Function, Number of custom type)
For example you can extend all arrays with property sum:
const arrayPrototype = Array.prototype
Object.defineProperty(arrayPrototype, 'sum', {
get() { return this.reduce((a,b) => a + b, 0) }
})
When you've executed the chunk of code, all arrays have the property:
console.log([1,3,-1,10].sum) // prints 13

Prototypal inheritance in JS and how to get parent properties

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.

Javascript: What are multi-level prototype hierarchies and why we should avoid it

In the Google Javascript Coding Guidelines, it said that we should not use Multi-level prototype hierarchies because "These hierarchies are much harder to get right than they first appear!". Actually I didn't get what it means. Where can I find a good example to explain its usage and illustrate its bad effect?
This is an example of two-level inheritance:
// 1. level constructor
var Dog = function ( name ) {
this.name = name;
};
Dog.prototype.bark = function () { /* ... */ };
// 2. level constructor
var TrainedDog = function ( name, level ) {
Dog.apply( this, arguments ); // calling the super constructor
this.level = level;
};
// set up two-level inheritance
TrainedDog.prototype = Object.create( Dog.prototype );
TrainedDog.prototype.constructor = TrainedDog;
TrainedDog.prototype.rollOver = function () { /* ... */ };
// instances
var dog1 = new Dog( 'Rex' );
var dog2 = new TrainedDog( 'Rock', 3 );
Here, dog1 inherits the bark method from the Dog prototype, and dog2 inherits both that method (from the Dog prototype) and the rollOver method from the TrainedDog prototype.
I believe the article is referring to not manually setting up the prototype chains but using a library, like goog.inherits or util.inherits
manually you would have to do
var Child = function Child() { ... };
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
// for some common value of extend
extend(Child.prototype, {
...
});
This can be simplified to
var Child = function Child() { ... };
goog.inherits(Child, Parent);
extend(Child.prototype, {
...
});
Note here goog.inherits also deals with Object.create emulation in legacy browsers.
This is because of prototype chain resolution problem. When you have something like foo.bar it doesn't mean that bar property belongs directly to foo object, so it start to search for bar in prototype chain of foo. If chain is long then property resolution could be relatively long operation.

Categories