2011-05-10 12 views
10

¿Cómo extendería una clase usando CoffeeScript, pero los argumentos de construcción pasarían a super?Extender la clase y pasar todos los argumentos del constructor a super

Ej:

class List extends Array 
    # Some other stuff to make it work... 

list = new List(1,2,3) 

console.log list 
 
[1, 2, 3] 
+0

¿No sería agradable para dividir esta pregunta en dos separados; el primero para el paso general de los argumentos constructor a super, el segundo sobre el comportamiento extraño de 'Array'? – Mitja

Respuesta

8
class List extends Array 
    constructor: -> 
     @push arguments... 

    toString: -> 
     @join('-') 

list = new List(1, 2) 

list.push(3) 

list.toString() 

=>

 
'1-2-3' 
+0

Sería bueno tener una manera genérica de pasar todos los argumentos al constructor del objeto padre, pero esto hace el trabajo para este caso :) – Acorn

+1

Debido a que Array no tiene un método de 'constructor', no es posible ... pero sí , sería bueno. =) – jejacks0n

+0

Esto no funciona en modo estricto, ya que "argumentos" no existe en ese caso. – monokrome

24

En general, esto funcionaría sin código adicional; el constructor matriz se utiliza menos que se modifique expresamente:

class A 
    constructor: -> 
    console.log arg for arg in arguments 

class B extends A 

new B('foo') # output: 'foo' 

Y el problema no es que la matriz no tiene un método constructor:

coffee> Array.constructor 
[Function: Function] 

El problema es simplemente que es Arraysimplemente extraño. Si bien las matrices son "solo objetos" en principio, en la práctica se almacenan de forma diferente. Por lo tanto, cuando intenta aplicar ese constructor a un objeto que no es una matriz (incluso si supera la prueba instanceof Array), no funciona.

Entonces, puede usar la solución de Acorn, pero luego puede encontrarse con otros problemas en el futuro (especialmente si pasa un List a algo que espera una verdadera matriz). Por esa razón, recomendaría implementar List como un contenedor alrededor de una instancia de matriz, en lugar de tratar de usar la herencia de un tipo de objeto nativo.

Mientras estamos en el tema, una aclaración muy importante : Cuando se utiliza super por sí mismo, que hace pase todos los argumentos! Este comportamiento es tomado prestado de Ruby. Así

class B extends A 
    constructor: -> 
    super 

pasará a lo largo de todos los argumentos a A 's constructor, mientras

class B extends A 
    constructor: -> 
    super() 

invocarán A' s constructor con no hay argumentos.

+0

¡Gracias por la fantástica explicación! '" Recomiendo implementar List como un contenedor alrededor de una instancia de matriz "' ¿Cómo harías para hacer esto? ¡Un pequeño ejemplo sería muy apreciado si tienes tiempo! – Acorn

+0

Bueno, solo quiero decir que el constructor se parecería a '@arr = Array :: slice.call arguments, 0' (método estándar de conversión de un método de argumentos a un objeto), luego implementaría cada uno de los métodos de matriz como simples pases (por ejemplo, 'push: -> @ arr.push.apply arr, arguments', 'toString: -> @ arr.toString()', ...), y finalmente agrega tu propia 'List' métodos. –

+0

Oh, vaya, pasando por cada método individualmente ... eso suena un poco tedioso :) – Acorn

-1

En mi exploración de JavaScript requirió una forma genérica para crear una clase con un número dinámico de argumentos de constructor. Como he mencionado, esto no funcionará para array, que yo sepa, solo funcionará para las clases de estilo coffee-script.

Llamar a una función específica con una serie dinámica de argumentos es bastante fácil a través .apply

args = [1, 2, 3] 
f = measurement.clone 

f.apply measurement, args 

Una clase puede extender una clase guardado en una variable. Como resultado, podemos escribir una función que devuelva nuevas subclases.

classfactory = (f) -> 
    class extension extends f 

Poniendo todo junto, podemos crear una función que devuelve nuevas subclases en la que los apply argumentos al constructor de la superclase.

classwitharguments = (f, args) -> 
    class extension extends f 
     constructor:() -> 
      extension.__super__.constructor.apply @, args 

Para utilizar esta nueva fábrica

args = [1, 2, 3] 
instance = new (classwitharguments Measurement, args) 

Pensamientos? ¿Comentarios? Sugerencias? ¿Limitaciones en las que no pensé? Házmelo saber.

2

El uso de extends en CoffeeScript espera que la superclase esté en CoffeeScript también. Si usa una clase que no sea CS, p. Array en la pregunta original, entonces puede encontrar problemas.

Esto resolvió el caso general para mí. Es un truco porque usa _super, que probablemente no está destinado a ser utilizado en el JS compilado.

class MyClass extends SomeJsLib 

    constructor: -> 
    _super.call @, arg1, arg2 

O si lo que desea es pasar a través de los argumentos de la persona que llama:

class MyClass extends SomeJsLib 

    constructor: -> 
    _super.apply @, arguments 
Cuestiones relacionadas