2011-12-23 6 views
8

Estoy tratando de hacer que el constructor aborte la construcción del objeto si algo falla, por ejemplo, no puede obtener un control de un lienzo.¿Cómo devolver nulo desde un constructor llamado con nuevo en Javascript?

Veo que klass() siempre devuelve this independientemente de cualquier retorno nulo o cualquier otro valor, ¿puedo solucionar esto para devolver nulo?

Ahora que lo pienso, una solución puede ser crear la nueva instancia dentro de klass() y devolver esa instancia o nulo, y no usar new, ¿hay una mejor solución?

function klass(canvas_id) { 
    var canvas = document.getElementById(canvas_id); 

    if(! (canvas && canvas.getContext)) { 
     return null; 
    } 
} 
var instance = new klass('wrong_id'); 
console.log(instance, typeof instance); 
+1

Puede lanzar una excepción o puede establecer un estado en su objeto que pueda probarse – jfriend00

Respuesta

12

Se podría hacer una "función de fábrica" ​​o "método de fábrica estática" en lugar:

Foo.CreateFoo = function() { 
    // not to confuse with Foo.prototype. ... 
    if (something) { 
    return null; 
    } 
    return new Foo(); 
}; 

// then instead of new Foo(): 
var obj = Foo.CreateFoo(); 

lo mismo usando la sintaxis nueva clase:

class Foo { 
    static CreateFoo() { 
    if (something) { 
     return null; 
    } 
    return new Foo(); 
    } 
} 
+0

Creo que algunas variaciones de esto generalmente serían un mejor enfoque. Intenta agarrar el elemento en una función, y si se encuentra uno, pásalo al constructor. Si no, devuelve nulo. –

10

La mejor solución sería la de lanzar un error:

function klass(canvas_id) { 
    var canvas = document.getElementById(canvas_id); 

    if(! (canvas && canvas.getContext)) { 
     throw new Error('Not a canvas'); 
    } 
} 

// later... 

try { 
    var c = new klass("canvas_id"); 
} catch(E) { 
    // error caught 
} 

EDIT: constructores pueden ser "obligados" a no devolver una instancia:

function Foo() { 
    var canvas = ...; 

    if ('undefined' == '' + Foo.CANVAS_CHECK) 
     Foo.CANVAS_CHECK = (canvas && canvas.getContext); 

    if (!Foo.CANVAS_CHECK) 
     return []; // the constructor will actually return an empty array 

    // passed; initialize instance here 
} 


// later on... 

var foo; 

if (!((foo = new Foo()) instanceof Foo)) { 
    // Failed. Canvas is unsupported. 
} 

// You happy now, am not i am? ;-) 

Lo curioso es, sin embargo, que si un "constructor" devuelve un número, cadena, true, false, etc., realmente hace devolver una instancia. La segunda solución solo funciona cuando el constructor devuelve una matriz vacía [] o un objeto vacío {}.

+1

¿Realmente le gustaría desordenar su código con declaraciones 'try/catch' solo para probar si un elemento w ¿como se encuentra? –

+1

No para verificar si se encontró un elemento. Pero si intentas validar si un lienzo es realmente compatible, prefiero generar una excepción. –

+0

Sí, está bien. Aunque como @amnotiam dice, me gustaría más un solo trazador de líneas como 'if (! (A = new klass ('id'))' – Petruza

2

Usted puede utilizar combinar una fábrica con el constructor en una función usando la técnica descrita en John Resig's article. Ejemplo:

function Person(name) { 
    var me = arguments.callee; 

    if (!(this instanceof me)) { 
     // factory code 

     // validate parameters.... 
     if(!name.match(/^[a-z]+$/)) 
      return null; 

     // ...and call the constructor 
     return new me(arguments); 

    } else { 

     // constructor code 
     this.name = name;  

    } 
} 


a = Person("joe") // ok 
b = Person("bob") // ok 
c = Person("R2D2") // null 
+0

+1 no solo para copiar sino para otorgarle crédito donde corresponde. (Y probablemente también el mejor delineador resultante, aún). –

0

Como he publicado en mi comentario anterior ...

function klass(canvas_id) { 
    var canvas = document.getElementById(canvas_id); 

    if(! (canvas && canvas.getContext)) { 
     return new Boolean; 
    } 
} 

var instance1 = new klass('wrong_id'); 

if(!(instance1 instanceof klass)) 
    console.log('Canvas is not suppored'); 

var instance2 = new klass('wrong_id').valueOf(); 

console.log(instance2, typeof instance2); 

if(instance2 !== false) 
    console.log('Canvas is supported, yeah'); 
Cuestiones relacionadas