2012-05-12 17 views
6

Básicamente, tengo un constructor de esta manera:pasar todos los argumentos a un constructor

function A() { 
    this.content = toArray(arguments); // toArray converts it to an array 
} 

me gustaría llamarlo desde otra función:

function B() { 
    return new A(); 
} 

El problema es, que había desea pasar todos los argumentos pasados ​​a B, a A también.

no puedo usar apply (de un modo común):

  • No habrá un constructor si sólo apply a cualquier objeto viejo
  • no puedo apply a la prototype, a menos que haya una manera fácil de clonarlo que no sé sobre
  • No puedo simplemente crear un new A para pasarlo de nuevo; en realidad, A() lanza si no se pasa ningún argumento, y me gustaría mantener esta funcionalidad.

Yo he llegado con algunas soluciones:

  • otro constructor!

    function C() {} 
    C.prototype = A.prototype; 
    
    function B() { 
        var obj = new C(); 
        A.apply(obj, arguments); 
        return obj; 
    } 
    
  • Otra función!

    function _A(_arguments) { 
        if(_arguments.length === 0) { 
         return this; 
        } 
    
        // Do initialization here! 
    } 
    
    _A.prototype.constructor = A; 
    
    function A() { 
        if(arguments.length === 0) { 
         throw new Error("That's not good."); 
        } 
    
        return new _A(toArray(arguments)); 
    } 
    
    function B() { 
        return new _A(toArray(arguments)); 
    } 
    
  • El resto de ellos son más o menos lo mismo en un formato diferente

Pero hay una manera muy fácil y obvio para hacer esto?

Respuesta

7

En las implementaciones de ES5, puede usar Object.create para crear el objeto que hereda de A.prototype, luego .apply() el objeto resultante para el constructor.

function A() { 
    this.content = toArray(arguments); // toArray converts it to an array 
} 

function B() { 
    var obj = Object.create(A.prototype); 
    A.apply(obj, arguments); 
    return obj; 
} 

Posteriormente, se podría acuñar Object.create para las implementaciones que no las soportan.

if (!Object.create) 
    Object.create = function(proto) { 
     function f() {} 
     f.prototype = proto; 
     return new f; 
    } 

Por supuesto, no es una cuña completa, pero es suficiente para lo que necesita.


O puede crear una función que efectivamente hace todo por usted.

function apply_constructor(constr, args) { 
    var obj = Object.create(constr.prototype); 
    constr.apply(obj, args); 
    return obj; 
} 

Y utilizar de esta manera:

function B() { 
    return apply_constructor(A, arguments); 
} 
+0

'Object.create' es perfecto. ¡Gracias! – Ryan

+0

@minitech: De nada. –

2

En ES5, puede utilizar aprieto.

function B() { 
    var args = Array.prototype.slice.call(arguments); 
    var curriedCtor = Function.prototype.bind 
     .apply(A, [null].concat(args)); 
    return new curriedCtor(); 
} 

por lo que con

function A(x, y) { 
    this.x = x; 
    this.y = y; 
} 

var test = B(1, 2); 

alert(JSON.stringify(test)); // alerts {"x":1,"y":2} 
Cuestiones relacionadas