2008-10-22 10 views
9

He estado tratando de aprender a agregar pruebas al código existente, actualmente leyendo Working Effectively With Legacy Code. He intentado aplicar algunos de los principios en JavaScript, y ahora estoy tratando de extraer una interfaz.¿Existe una forma "correcta" de hacer herencia en JavaScript? Si es así, ¿qué es?

Al buscar la creación de interfaces en JavaScript, no puedo encontrar mucho, y lo que encuentro sobre la herencia parece ser que hay varias formas diferentes. (Algunas personas crean sus propias clases base para proporcionar métodos útiles para facilitar la herencia, algunas funciones de uso y algunos prototipos de uso).

¿Cuál es el camino correcto? ¿Tienes un ejemplo simple para extraer una interfaz en JavaScript?

Respuesta

13

No hay manera correcta, porque tantas personas hacen tantas cosas diferentes .. Hay muchos patrones útiles.

Crockford sugiere que "vaya con el grano", o escriba javascript de una manera que corresponda a la naturaleza prototípica de JavaScript.

Por supuesto, continúa demostrando que el modelo original que sugirió Netscape está realmente roto. Él lo etiqueta como "pseudoclassical", y señala una gran cantidad de errores de dirección y la complejidad innecesaria que implica seguir ese modelo.

Escribió la función "objeto" como un remedio (ahora conocido como Object.create()). Permite algunos patrones prototípicos muy potentes.

No siempre es fácil desarrollar una interfaz limpia cuando tiene que trabajar con javascript heredado, especialmente no cuando se trata de sistemas grandes, que generalmente incluyen bibliotecas múltiples y cada uno implementa un estilo único y un patrón de herencia diferente. En general, diría que la "forma correcta" de hacer herencia es la que le permite escribir una interfaz limpia que se comporta bien en el contexto de su código heredado, pero también le permite refactorizar y eliminar antiguas dependencias con el tiempo. .

Teniendo en cuenta las diferencias entre los principales patrones de la biblioteca, he descubierto que la ruta más exitosa para realizar en mi propio trabajo es mantener mis interfaces independientes de las interfaces de la biblioteca por completo. Usaré una biblioteca o módulo si es útil, pero no estaré vinculado a él. Esto me ha permitido refactorizar una gran cantidad de código, eliminar algunas bibliotecas y utilizar bibliotecas como andamios que se pueden optimizar más adelante.

En esta línea, he escrito interfaces inspiradas en el patrón de herencia parasitaria de Crockford. Realmente es una victoria para la simplicidad.

En el otro lado de la moneda, estoy seguro de que podría abogar por elegir una biblioteca, imponerla en su equipo y cumplir tanto con sus patrones de herencia como con sus convenciones de interfaz.

+2

¿Qué tal unos enlaces? – pc1oad1etter

3

También echa un vistazo a Dean Edwards 'Base.js. Puedes echarle un vistazo here, la publicación del blog se explica por sí misma.

5

Estás viendo dos cosas diferentes.

Primero tiene interfaces. La forma más aceptada de implementar esto es a través de Duck Typing ("si se ve como un pato y grazna como un pato, entonces es un pato"). Esto significa que si un objeto implementa un conjunto de métodos de la interfaz, entonces es esa interfaz. Implementa esto teniendo una matriz de nombres de métodos que definen una interfaz. Luego, para verificar si un objeto implementa esa interferencia, verá si implementa esos métodos.Aquí está un ejemplo de código que Instigó:

function Implements(obj, inter) 
{ 
    var len = inter.length, i = 0; 
    for (; i < len; ++i) 
    { 
     if (!obj[inter[i]]) 
      return false; 
    } 
    return true; 
} 

var IUser = ["LoadUser", "SaveUser"]; 

var user = { 
     LoadUser : function() 
     { 
      alert("Load"); 
     }, 

     SaveUser : function() 
     { 
      alert("Save"); 
     } 
    }; 

var notUser = { 
     LoadUser : function() 
     { 
      alert("Load"); 
     } 
    }; 

alert(Implements(user, IUser)); 
alert(Implements(notUser, IUser)); 

Ahora usted tienen herencia. JS no tiene herencia incorporada; entonces debes implementarlo manualmente. Esto es solo una cuestión de "copiar" las propiedades de un objeto a otro. He aquí otro ejemplo de código (no es perfecto pero demuestra el punto):

function InheritObject(base, obj) 
{ 
    for (name in base) 
    { 
     if (!obj[name]) 
      obj[name] = base[name]; 
    } 
} 

var Base = { 
     BaseFunc : function() { alert("BaseFunc from base"); }, 
     InheritFunc : function() { alert("InheritFunc from base"); } 
    } 

var Inherit = { 
     InheritFunc : function() { alert("InheritFunc from inherit"); }, 
     AnotherFunc : function() { alert("AnotherFunc from inherit"); } 
    } 

InheritObject(Base, Inherit); 

Inherit.InheritFunc(); 
Inherit.BaseFunc(); 
Inherit.AnotherFunc(); 

Base.BaseFunc(); 
Base.InheritFunc(); 

Es probable que desee ver en http://www.mootools.net. Tiene mi implementación favorita de Clases. También quiere definitivamente echa un vistazo a "Pro Patrones Javascript Diseño"

http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X

Este libro entra en detalles acerca de cómo buena para emular programación orientada a objetos en javascript.

+0

+1 ¡Explicación simple y clara! –

6

No hay clases en javascript, solo objetos.
Pero si insiste en emular el modelo orientado a objetos basado en la clase puede utilizar esta:

 
function ChildClass() { 
    ParentClass.call(this); 
    // Write the rest of your constructor function after this point. 
}; 
ChildClass.prototype = jQuery.extend({}, ParentClass.prototype, ChildClass.prototype); 

jQuery.extend es una función de 'copia superficial' de la biblioteca jQuery. Puede reemplazarlo con cualquier otra función de copia/clonación de objetos.

+1

la primera oración no se puede enfatizar más – Claudiu

0

Prototype ofrece su propia visión de la herencia, de http://www.prototypejs.org/api/class/create:

var Animal = Class.create({ 
    initialize: function(name, sound) { 
    this.name = name; 
    this.sound = sound; 
    }, 

    speak: function() { 
    alert(this.name + " says: " + this.sound + "!"); 
    } 
}); 

// subclassing Animal 
var Snake = Class.create(Animal, { 
    initialize: function($super, name) { 
    $super(name, 'hissssssssss'); 
    } 
}); 
Cuestiones relacionadas