2011-12-23 22 views
8

Próbuję zmusić konstruktora do przerwania konstrukcji obiektu, jeśli coś się nie powiedzie, na przykład nie może uzyskać uchwytu płótna.Jak zwrócić null z konstruktora o nazwie new w JavaScript?

Ale jak używam new Widzę, że klass() zawsze zwraca this niezależnie od jakiejkolwiek wartości zwracanej null lub jakiejkolwiek innej wartości, czy mogę obejść to, aby zwrócić zero?

Teraz myślę, że rozwiązaniem może być stworzenie nowej instancji wewnątrz klass() i zwrócenie tej instancji lub wartości zerowej, a nie użycie new, czy istnieje lepsze rozwiązanie?

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

Możesz rzucić wyjątek lub ustawić jakiś stan w obiekcie, który można przetestować – jfriend00

Odpowiedz

12

Można zrobić „funkcją fabryka” lub „metoda statyczna fabryki” zamiast:

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(); 

samo przy użyciu nowszej klasy składni:

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

Myślę, że niektóre warianty na tym ogólnie byłyby lepszym podejściem. Spróbuj pobrać element w funkcji, a jeśli zostanie znaleziony, przekaż go do konstruktora. Jeśli nie, zwróć wartość null. –

10

Lepszym rozwiązaniem byłoby wyrzucić błąd:

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: Konstruktorzy mogą być "zmuszony" do nie wrócić instancję:

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? ;-) 

Dziwne jest jednak to, że jeśli "konstruktor" zwróci liczbę, ciąg znaków, true, false itd., To faktycznie powoduje, że zwraca instancję. Drugie rozwiązanie działa tylko wtedy, gdy konstruktor zwróci pustą tablicę [] lub pusty obiekt {}.

+1

Czy naprawdę chcesz zagracać swój kod za pomocą instrukcji 'try/catch', aby sprawdzić, czy element w jak znaleźć? –

+1

Nie sprawdzać, czy element został znaleziony. Ale jeśli próbujesz sprawdzić poprawność, czy płótno jest faktycznie obsługiwane, wolę zgłosić wyjątek. –

+0

Tak, jest dobrze. Chociaż jak @amnotiam mówi, chciałbym mieć lepszy liniowiec jak 'if (! (A = nowy klass ('id'))' – Petruza

2

Można użyć połączyć fabrykę z konstruktor w jednej funkcji przy użyciu techniki opisanej w John Resig's article. Przykład:

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 za nie tylko kopiowanie, ale udzielenie kredytu tam, gdzie jest to konieczne. (I prawdopodobnie również najlepszy wynikowy jednolinijkowy, jeszcze.) –

0

Jak napisałem w moim komentarzu powyżej ...

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'); 
Powiązane problemy