2012-03-24 18 views
32

Soy un programador que ha programado en varios idiomas, tanto funcional como orientado a OO. También programé algo de Javascript, pero nunca usé (ni tuve que usar) el polimorfismo.¿Debo usar polimorfismo en javascript?

Ahora, como un proyecto de hobby, me gustaría portar algunas aplicaciones que fueron escritas en Java y C# que usan mucho polimorfismo para Javascript.

Pero a primera vista, leí un montón de 'Es posible, pero ...'

Entonces, ¿hay una alternativa a ella?

Un ejemplo de lo que me gustaría escribir en JS en pseudolang:

abstract class Shape{ { printSurface() } ; } 

class Rect : Shape() { printSurface() { print (sideA*sideB}} 

class Circle : Shape() { printSurface() { print { pi*r*r }} 

TheApp { myshapes.iterate(shape s) {s.printSurface() } } 

lo tanto un caso clásico polimórfica: la iteración en la clase base.

Me gustaría lograr este tipo de comportamiento. Sé que es polimorfismo, pero ¿hay algún otro "patrón" que pase por alto que logre este tipo de comportamiento o debería estudiar las posibilidades de herencia en Javascript?

Respuesta

43

Como he dicho, JavaScript es un lenguaje de tipeo dinámico basado en herencia prototípica, por lo que no puede usar el mismo enfoque de los lenguajes escritos.Una versión JS de lo que ha escrito, podría ser:

function Shape(){ 
    throw new Error("Abstract class") 
} 

Shape.prototype.printSurface = function() { 
    throw new Error ("Not implemented"); 
} 

function Rect() { 
    // constructor; 
} 

Rect.prototype = Object.create(Shape.prototype); 
Rect.prototype.printSurface = function() { 
    // Rect implementation 
} 

function Circle() { 
    // constructor; 
} 

Circle.prototype = Object.create(Shape.prototype); 
Circle.prototype.printSurface = function() { 
    // Circle implementation 
} 

Luego, en su aplicación:

var obj = new Circle(); 

if (obj instanceof Shape) { 
    // do something with a shape object 
} 

O, con pato a escribir:

if ("printSurface" in obj) 
    obj.printSurface(); 

// or 

if (obj.printSurface) 
    obj.printSurface(); 

// or a more specific check 
if (typeof obj.printSurface === "function") 
    obj.printSurface(); 

frías también tiene Shape como objeto sin ningún constructor, que es más "clase abstracta" como:

var Shape = { 
    printSurface : function() { 
     throw new Error ("Not implemented"); 
    } 
} 

function Rect() { 
    // constructor; 
} 

Rect.prototype = Object.create(Shape); 
Rect.prototype.printSurface = function() { 
    // Rect implementation 
} 

function Circle() { 
    // constructor; 
} 

Circle.prototype = Object.create(Shape); 
Circle.prototype.printSurface = function() { 
    // Circle implementation 
} 

en cuenta que en este caso, no se puede utilizar instanceof más, así que o se vuelve a los tipificación de pato o usted tiene que utilizar isPrototypeOf, pero está disponible sólo en los últimos navegadores:

if (Shape.isPrototypeOf(obj)) { 
    // do something with obj 
} 

Object.create no está disponible en navegador que no implementa las especificaciones de ES5, pero puede usar fácilmente un relleno múltiple (consulte el enlace).

+0

Tx, muy buena respuesta. Pero pragmáticamente, iré por JOOSE, el marco de clase. – Peter

+0

Esto no funciona para Document. Quería crear NMLDocument que hereda de Document, pero apareció un extraño error '[LenientThis]'. – m93a

14

El "patrón" en juego aquí sería "interfaz". Siempre que todos los objetos de la colección myshapes implementen el método printSurface(), todo irá bien.

Como Javascript es un lenguaje de tipeo dinámico, los objetos en una colección no necesitan estar relacionados en absoluto.

+1

yes rings a bell, python like? – Peter

+1

Incluso el mismo ejemplo que he usado se muestra aquí: http://knol.google.com/k/programming-to-the-interface-in-javascript-yes-it-can-be-done-er-i- falso medio # – Peter

+1

No entiendo por qué esta respuesta no se sube más. Señala la verdad simple sobre JavaScript y su polimorfismo es simplemente nombrar las propiedades de la misma manera. No hay restricciones de tipo de qué preocuparse. – hayavuk

7

sé que esto se puede hacer con prototipos pero no soy un experto en su uso. i prefer the object literal approach (más fácil de visualizar y tiene un ámbito "privado")

//shape class 
var shape = function() { 
    //return an object which "shape" represents 
    return { 
     printSurface: function() { 
      alert('blank'); 
     }, 
     toInherit: function() { 
      alert('inherited from shape'); 
     } 
    } 
}; 

//rect class 
var rect = function() { 
    //inherit shape 
    var rectObj = shape(); 

    //private variable 
    var imPrivate = 'Arrr, i have been found by getter!'; 

    //override shape's function 
    rectObj.printSurface = function(msg) { 
     alert('surface of rect is ' + msg); 
    } 

    //you can add functions too 
    rectObj.newfunction = function() { 
     alert('i was added in rect'); 
    } 

    //getters and setters for private stuff work too 
    rectObj.newGetter = function(){ 
     return imPrivate; 
    } 

    //return the object which represents your rectangle 
    return rectObj; 
} 



//new rectangle 
var myrect = rect(); 

//this is the overridden function 
myrect.printSurface('foo'); 

//the appended function 
myrect.newfunction(); 

//inherited function 
myrect.toInherit(); 

//testing the getter 
alert(myrect.newGetter()); 

+0

Tengo que ver más tarde, pero siempre +1 por lo que hace el esfuerzo de proporcionar codedamples! – Peter

+1

@Weston: ¿no es eso lo suficientemente sujeto como para ser una respuesta separada? Los marcos se pueden discutir allí que. Por ahora: ¿la penalización de rendimiento es siempre aceptable? – Peter

4

Como dice Weston, si usted no tiene la necesidad de herencia entonces la naturaleza de pato-mecanografiada de un lenguaje dinámico, como Javascript le da polimorfismo ya que no hay un requisito en el lenguaje mismo para una clase base o interfaz fuertemente tipada.

Si desea utilizar la herencia y hacer cosas como llamar fácilmente a la implementación de una superclase, esto se puede lograr con prototipos o literales de objetos como lo muestra Joeseph.

Otra cosa sería mirar Coffescript ya que esto se compila en Javascript y le da toda la bondad de OO en una sintaxis simple. Escribirá todas las cosas de creación de prototipos de bollerplate para usted. La desventaja es que agrega este paso de compilación adicional. Dicho esto, escribir una jerarquía de clases simple como su ejemplo anterior y luego ver qué javascript aparece como resultado ayuda a mostrar cómo se puede hacer todo.

+0

Coffeescript Lo sé, pero el paso de compilación es demasiado para mí ... – Peter

4

En otra nota. Si desea programar Javascript en un estilo OO usando clases, puede buscar en los muchos "sistemas de clases" para Javascript. Un ejemplo es Joose (http://joose.it).

Muchos frameworks del lado del cliente implementan su propio sistema de clases. Un ejemplo de esto es ExtJS.

+2

probándolo ahora, es realmente muy bueno – Peter

+0

O simplemente olvida las clases y abraza los objetos. – hayavuk