2012-05-12 17 views
6

Fondamentalmente, ho un costruttore come questo:Passando tutti gli argomenti a un costruttore

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

mi piacerebbe chiamarlo da un'altra funzione:

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

Il problema è, mi piacerebbe piace passare tutti gli argomenti passati a B, a A pure.

posso non uso apply (in un modo comune):

  • Non sarà un costruttore se ho appena apply a qualsiasi vecchio oggetto
  • non posso apply al prototype, a meno che non ci sia un modo semplice per clonarlo che non conosco
  • Non riesco a creare un nuovo new A; in realtà, A() genera se non viene passato alcun argomento e vorrei mantenere questa funzionalità.

mi è venuta in mente un paio di soluzioni:

  • un altro costruttore!

    function C() {} 
    C.prototype = A.prototype; 
    
    function B() { 
        var obj = new C(); 
        A.apply(obj, arguments); 
        return obj; 
    } 
    
  • Un'altra funzione!

    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)); 
    } 
    
  • Il resto di loro sono più o meno la stessa cosa in un formato diverso

Ma c'è un modo molto semplice e ovvio per fare questo?

risposta

7

Nelle implementazioni ES5, è possibile utilizzare Object.create per creare l'oggetto che eredita da A.prototype, quindi .apply() l'oggetto risultante per il costruttore.

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

Poi si potrebbe shim Object.create per le implementazioni non-portante.

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

Ovviamente non è uno spessore completo, ma è sufficiente per quello che ti serve.


Oppure è possibile creare una funzione che fa effettivamente tutto per voi.

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

e usarlo in questo modo:

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

'Object.create' è perfetto. Grazie! – Ryan

+0

@minitech: prego. –

2

In ES5, è possibile utilizzare bind.

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

così 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} 
Problemi correlati