Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can someone explain javascript prototypal inheritance

Tags:

javascript

oop

I wonder if someone could be kind enough to explain the function.prototype thingie (thingie!!??) in OO javascript.

I come from a server side programming background, and may be I am not grasping the whole concept of prototypes,

Given the following snippets of code:

var animate=function(){};
animate.angular=function(){/*does something here*/};
animate.circular=function(){/*does something here*/};

And

var animate=function(){};
animate.prototype.angular=function(){/*does something here*/};
animate.prototype.circular=function(){/*does something here*/};

as far as I can tell, both the latter functions are callable via animate.angular(/*args*/) and animate.circular(/*args*/) so, I guess my question is, what are the merits of defining the functions in the second way? and how or why are they different?

Hope I made sense...

EDIT: Thankyou all for the enlightening answers, It's very hard to judge an answer here as being "Correct", so I'm gonna mark the one I feel made the most contribution...

You all have certainly given me more food for thought...

like image 662
ekhaled Avatar asked Nov 09 '09 20:11

ekhaled


1 Answers

I think you meant to set something equal to new animate() somewhere in your example. Without using new I'll elaborate a little on what happens:

var animate = function(){ console.log(0, 'animate'); };
animate.angular = function(){ console.log(1, 'animate.angular'); };
animate.circular = function(){ console.log(2, 'animate.circular'); };

animate.prototype.angular = function(){ console.log(3, 'animate.prototype.angular'); };
animate.prototype.circular = function(){ console.log(4, 'animate.prototype.circular'); };

Only the first two functions, #1 & #2, are callable from the animate variable.

animate.angular();
animate.circular();

If you create a new animate() you can call the next two, #3 & #4, (but not #1 or #2).

var ani2 = new animate();

ani2.angular();
ani2.circular();

Also, animate() is a function but ani2 is not.

console.log(5, typeof animate);
console.log(6, typeof ani2);
console.log(7, animate());

Although ani2 has already been created, you can add new members to it via the animate.prototype.

animate.prototype.bark = function(){ console.log(8, 'bark'); };
ani2.bark();

The animate variable doesn't inherit form it's prototype however.

console.log(9, typeof ani2.bark);
console.log(10, typeof animate.bark);

Note that ani2 doesn't inherit members applied directly to the animate variable. It only inherits from animate.prototype.

animate.paperclip = function(){ console.log(11, "paperclip"); };

animate.paperclip();
console.log(12, typeof ani2.paperclip);
console.log(13, typeof animate.paperclip);

You can also use the the this keyword inside a constructor function like animate to add instance members to new children.

var Anime = function(a,b){ this.a=a; this.b=b; this.c=console; };
var anime1 = new Anime(14, 'anime1');
var anime2 = new Anime(15, 'anime2');
anime1.c.log(anime1.a, anime1.b);
anime2.c.log(anime2.a, anime2.b);

Anime.prototype.a = 16;
Anime.prototype.z = 'z';

var anime3 = new Anime(17, 'anime3');
anime3.c.log(18, anime3.a, anime3.b, anime3.z, " ", anime2.a, anime2.b, anime2.z, " ", anime1.a, anime1.b, anime1.z);
anime2.z='N';
anime3.c.log(19, anime3.a, anime3.b, anime3.z, " ", anime2.a, anime2.b, anime2.z, " ", anime1.a, anime1.b, anime1.z);

Memory was automatically allocated for a separate instance of anime2.z only because it was modified, anime1 & anime3 still "share" a thrifty unmodified z.

The a, b, and c members are not "communal" in the same way. They were allocated immediately using this in the constructor, new Anime(), (not inherited from Anime.prototype). Also, the a member on the prototype would always be "individualized" by the constructor.

Never forget the new keyword or none of it works like it should. For example, this points to the global object in a constructor called without new.

console.log(20, typeof window.a, typeof window.b, typeof window.c);
var opps = Anime(21, 'zapp');
console.log(22, typeof window.a, typeof window.b, typeof window.c);
console.log(23, typeof opps);

Here's the output. And a second for Tom's suggesting the Douglas Crockford videos!


/*
1 animate.angular
2 animate.circular
0 animate
3 animate.prototype.angular
4 animate.prototype.circular
5 function
6 object
0 animate
7 undefined
8 bark
9 function
10 undefined
11 paperclip
12 undefined
13 function
14 anime1
15 anime2
18 17 anime3 z 15 anime2 z 14 anime1 z
19 17 anime3 z 15 anime2 N 14 anime1 z
20 undefined undefined undefined
22 number string object
23 undefined
*/
like image 105
machine elf Avatar answered Sep 24 '22 00:09

machine elf