2009-11-09 4 views
7

Je me demande si quelqu'un pourrait être assez aimable pour expliquer le function.prototype thingie (thingie !! ??) dans OO javascript.Quelqu'un peut-il expliquer javascript prototypal héritage

Je viens d'un milieu de programmation côté serveur, et peut-être que je ne suis pas saisir le concept de prototypes,

Compte tenu des extraits de code suivants:

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

Et

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

autant que je peux dire, les deux fonctions sont appelables via animate.angular(/*args*/) et animate.circular(/*args*/) alors, je suppose que ma question est, quelles sont les mer c'est de définir les fonctions de la deuxième manière? et comment ou pourquoi sont-ils différents?

Espoir Je sens ... fait

EDIT: Merci à tous pour les réponses éclairantes, il est très difficile de juger une réponse ici comme étant « correct », alors je vais marquer celui que je me sens a le plus contribué ...

Vous avez tous certainement me donner plus de nourriture pour la pensée ...

+3

Une autre excellente réponse qui explique en grande partie l'héritage Prototypical (en particulier par JavaScript): http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript/1598077 # 1598077 –

+2

Voir aussi: http://stackoverflow.com/questions/186244/what-does-it-mean-that-javascript-is-a-prototype-based-language –

Répondre

6

Je pense que vous vouliez mettre quelque chose égal à ANIMÉE() quelque part dans votre exemple. Sans l'aide nouvelle Je vais élaborer un peu sur ce qui se passe:

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

Seules les deux premières fonctions, # 1 & # 2, sont remboursables par anticipation de la variable Animer.

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

Si vous créez un ANIMÉE() vous pouvez appeler les deux suivants, # 3 & # 4, (mais pas n ° 1 ou n ° 2).

var ani2 = new animate(); 

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

De même, animate() est une fonction mais ani2 ne l'est pas.

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

Bien que ANI2 a déjà été créé, vous pouvez ajouter de nouveaux membres via le animate.prototype.

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

La variable d'animation n'hérite pas de son prototype.

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

Notez que ani2 n'hérite pas des membres appliqués directement à la variable d'animation. Il hérite uniquement de animate.prototype.

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

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

Vous pouvez également utiliser le mot-clé du ce dans une fonction constructeur comme Animer pour ajouter des membres d'instance nouveaux enfants.

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

mémoire a été allouée automatiquement une instance distincte de anime2.z seulement parce qu'il a été modifié, anime1 & anime3 encore "partager" un non modifié Thrifty z.

Les membres a, b et c ne sont pas "communaux" de la même manière. Ils ont été alloués immédiatement en utilisant ce dans le constructeur, new Anime(), (pas hérité de Anime.prototype). De plus, le membre du prototype sera toujours "individualisé" par le constructeur.

N'oubliez jamais le nouveau mot-clé ou tout ne fonctionne pas comme il se doit. Par exemple, ce pointe vers l'objet global dans un constructeur appelé sans 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); 

Voici la sortie. Et une seconde pour Tom suggérant les vidéos de Douglas Crockford!


/* 
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 
*/ 
+0

Une convention largement utilisée que vous utilisez est également d'avoir une première lettre majuscule pour la fonction constructeur, ce qui permet de ne pas oublier le nouveau mot-clé. Un bon article sur l'héritage prototypique peut être trouvé ici: http://msdn.microsoft.com/en-us/magazine/ff852808.aspx –

2

Javascript est un langage bizarre ... très puissant mais pas du tout fortement structuré par rapport aux autres langues ..

Le prototype est la façon dont JavaScript vous permet d'économiser de la mémoire si vous créez plusieurs instances d'une classe ... Donc, si vous utilisez JS d'une manière OOP, vous devez définir vos fonctions dans le cadre du prototype. En outre, il existe des moyens de simuler l'héritage en utilisant le prototype.

Je recommande vivement le livre "Javascript, the Good Parts" pour beaucoup de bonnes explications à ce sujet.

+0

Il y a aussi un Google Tech Talk du même nom: http://www.youtube.com/watch?v=hQVTIJBZook Je viens de le regarder aujourd'hui. –

+1

@gunderson: "Bizarre" est une expression très subjective. Après avoir correctement appris JS pendant 6 mois, je me retrouve à programmer avec plus de fluidité et de manière plus naturelle qu'avec Java ou C++. Je ne peux donc pas être d'accord avec vous. –

+0

C'est pourquoi j'aime mootools, il expose l'héritage javascript avec un style que j'apprécie. –

2

Si vous pouvez épargner 3 heures de temps, je vous conseille de regarder les vidéos "The JavaScript Programming Language" de YUI Theatre. Le conférencier/enseignant est Douglas Crockford, et il vous donnera une base JS ferme sur laquelle vous pouvez construire.

Cordialement

Tom

3

Même si elle se sent parfois de cette façon, javascript ne pas les classes, mais travaille avec des prototypes. Vous définissez un prototype, vous pouvez ensuite créer des copies du prototype.

A partir de:

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

vous pouvez:

var a = new animate(); 
animate.angular();  // OK 
a.circular();   // error: a.circular is not a function 

Cependant, si vous commencez avec:

function animate(i){}; 
animate.prototype.angular = function() {}; 

vous pouvez maintenant

var a = new animate(); 
a.angular(); 

bien sûr c'est plus intéressant si vous avez des variables d'instance.

function animate(i) { 
    this.x = i; 
} 
animate.prototype.angular = function() { 
    this.x *= 2; 
} 

var a = new animate(5); 
a.angular(); 
console.log(a.x); // 10 
2

La POO basée sur le prototype vous offre des libertés.

Si vous voulez vraiment en savoir plus, comme beaucoup l'ont dit, lisez les explications de Crockford, vous n'obtiendrez pas de meilleure ressource que cela.

Si vous voulez des avantages rapides:

var Building = function() { 
    this.openDoor = function() {}; 
}; 

var House = function() { 
    this.closeDoor = function() {}; 
}; 
House.prototype = new Building(); 

var a = new House(); 
a.openDoor(); 
a.closeDoor(); 

Définition des objets (qui représentent ce que les classes sont dans d'autres langues) comme celui-ci est trop méchant, alors je vais inclure une petite astuce dans ma réponse:

la meilleure façon de construire votre système, est sous un espace de noms global choisi par vous, par exemple:

if (typeof MYAPP === 'undefined' || !MYAPP) { 
    var MYAPP = {}; 
} 

function New(className, classBody) { 
    // This adds your "classes" to this MYAPP namespace so they can be instantiated 
    // You need some magic here, so have fun with this function 
} 

New('Building', function() { 
    this.openDoor = function() {}; 
}); 

New('House', function() { 
    this.prototype = new MYAPP.Building(); 
    this.closeDoor = function() {}; 
}); 

// Now you can do the same as before but your application is cleaner :) 
var a = new MYAPP.House(); 
a.openDoor(); 
a.closeDoor(); 

Vive.