2009-11-09 729 views
7

Me pregunto si alguien podría ser tan amable de explicar el function.prototype thingie (thingie !! ??) en OO javascript.¿Alguien puede explicar la herencia prototípica de javascript?

Vengo de un fondo de programación del lado del servidor, y puede ser que no tengo agarrada todo el concepto de prototipos,

Teniendo en cuenta los siguientes fragmentos de código:

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

Y

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

por lo que puedo decir, ambas funciones se pueden llamar a través de animate.angular(/*args*/) y animate.circular(/*args*/) así que, supongo que mi pregunta es, ¿cuál es el mer es de definir las funciones de la segunda manera? y cómo o por qué son diferentes?

esperanza que tenía sentido ...

EDIT: Gracias a todos por las respuestas iluminadoras, es muy difícil juzgar una respuesta aquí como "correcta", así que voy a marcar el que yo siento hecho la mayor contribución ...

todos ustedes ciertamente me ha dado más que pensar ...

+3

Otra gran respuesta que explica en gran medida la herencia prototípica (específicamente wrt JavaScript): http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript/1598077 # 1598077 –

+2

Ver también: http://stackoverflow.com/questions/186244/what-does-it-mean-that-javascript-is-a-prototype-based-language –

Respuesta

6

creo que quería decir para establecer algo igual a nueva animado() algún lugar de su ejemplo. Sin utilizar nueva voy a elaborar un poco sobre lo que sucede:

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

Sólo las dos primeras funciones, # 1 & # 2, se puede llamar desde la variable animado.

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

Si crea una nueva animado() puede llamar a los dos siguientes, # 3 # 4 &, (pero no # 1 o # 2).

var ani2 = new animate(); 

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

Además, animate() es una función pero ani2 no lo es.

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

Aunque ani2 ya se ha creado, se puede añadir nuevos miembros a la misma a través de la animate.prototype.

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

Sin embargo, la variable de animación no hereda de su prototipo.

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

Tenga en cuenta que ani2 no hereda los miembros aplicados directamente a la variable animada. Solo hereda de animate.prototype.

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

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

También puede utilizar el la presente palabra clave dentro de una función constructora como animado a añadir a los miembros de instancia nuevos niños.

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

memoria se asigna automáticamente para una instancia independiente de anime2.z sólo porque se modificó, anime1 & anime3 todavía "compartir" una z no modificada ahorrativo.

Los miembros a, b y c no son "comunes" de la misma manera. Se asignaron inmediatamente usando este en el constructor, nuevo Anime(), (no heredado de Anime.prototype). Además, el miembro del prototipo siempre sería "individualizado" por el constructor.

Nunca olvide la nueva palabra clave o nada de eso funciona como debería. Por ejemplo, este apunta al objeto global en un constructor llamado sin nuevo.

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

Aquí está la salida. ¡Y un segundo para Tom sugiriendo los videos 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

Una convención ampliamente utilizado que está utilizando, así es tener una primera letra mayúscula de constructor de la función, lo que ayuda a no olvidar la nueva palabra clave. Un buen artículo sobre la herencia prototípica se puede encontrar aquí: http://msdn.microsoft.com/en-us/magazine/ff852808.aspx –

2

Javascript es un lenguaje extraño ... muy potente, pero no todo lo que fuertemente estructurada en comparación con otros idiomas ..

El prototipo es cómo JavaScript le permite guardar la memoria si va a crear varias instancias de una clase ... Por lo tanto, si usa JS de forma OOP, debe definir sus funciones como parte del prototipo. Además, hay formas de simular herencia usando el prototipo.

Recomiendo mucho el libro "Javascript, the Good Parts" para obtener una gran explicación sobre esto.

+0

también hay un Google Talk del Tech mismo nombre: http://www.youtube.com/watch?v=hQVTIJBZook Acabo de ver hoy en día. –

+1

@gunderson: "Weird" es una expresión muy subjetiva. Después de aprender correctamente JS durante 6 meses, me encuentro programando con más fluidez y más naturalmente que nunca usando Java o C++. No puedo, por lo tanto, estar de acuerdo contigo. –

+0

Es por eso que amo los mootools, expone la herencia de JavaScript con un estilo que aprecio. –

2

Si puede dedicar 3 horas, le aconsejo que eche un vistazo a los videos de "El lenguaje de programación de JavaScript" del Teatro YUI. El orador/profesor es Douglas Crockford, y él le dará una base firme de JS sobre la cual puede construir.

Saludos

Tom

3

A pesar de que se siente de esa manera a veces, javascript no tiene clases, pero trabaja con prototipos. Usted define un prototipo, luego puede crear copias del prototipo.

A partir de:

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

puede:

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

Sin embargo, si usted comienza con:

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

ahora puede hacerlo

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

por supuesto, esto es más interesante si tiene variables de instancia.

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

programación orientada a objetos basado en prototipos le da las libertades clase programación orientada a objetos no lo hace.

Si realmente desea aprender acerca de él, al igual que muchos dijeron, leer las explicaciones de Crockford, usted no recibirá recursos mejor que eso.

Si quieren beneficios rápidos:

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

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

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

objetos de definición (que representan lo que las clases están en otros idiomas) como esto es demasiado desagradable, así que incluirá un pequeño consejo en mi respuesta:

mejor manera de construir el sistema, es en virtud de un espacio de nombres global elegido por usted, por ejemplo:

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

Saludos.

Cuestiones relacionadas