2015-05-22 11 views
11

Uruchamiając ten fragment poprzez BabelJS:Rozszerzone Błędy nie masz wiadomość lub ślad stosu

class FooError extends Error { 
    constructor(message) { 
    super(message); 
    } 
} 

let error = new FooError('foo'); 
console.log(error, error.message, error.stack); 

wyprowadza

{} 

który nie jest to, czego oczekują. Uruchamianie

error = new Error('foo'); 
console.log(error, error.message, error.stack); 

produkuje

{} foo Error: foo 
    at eval (eval at <anonymous> (https://babeljs.io/scripts/repl.js?t=2015-05-21T16:46:33+00:00:263:11), <anonymous>:24:9) 
    at REPL.evaluate (https://babeljs.io/scripts/repl.js?t=2015-05-21T16:46:33+00:00:263:36) 
    at REPL.compile (https://babeljs.io/scripts/repl.js?t=2015-05-21T16:46:33+00:00:210:12) 
    at Array.onSourceChange (https://babeljs.io/scripts/repl.js?t=2015-05-21T16:46:33+00:00:288:12) 
    at u (https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js:28:185) 

który jest dokładnie to, co chciałbym z rozszerzonego błędu.

Moim celem jest rozszerzenie Error na różne podklasy i użycie ich w dopasowaniu bluebirda do catch. Jak na razie, to niestety się nie udaje.

Dlaczego podklasa nie pokazuje komunikatu lub śladu stosu?

Edytuj:using Chrome's built-in subclassing (dzięki @coder) działa idealnie. To nie jest specyficzna dla Babel, koniecznie, jak w poniższym przykładzie (od @loganfsmyth on Babel's gitter feed) pokazuje:

// Works 
new (function(){ 
    "use strict"; 
    return class E extends Error { } 
}()); 
// Doesn't 
new (function(){ 
    "use strict"; 
    function E(message){ 
    Error.call(this, message); 
    }; 
    E.prototype = Object.create(Error); 
    E.prototype.constructor = E; 
    return E; 
}()); 
+1

Nie sądzę, że to problem Babel. Jeśli użyjesz starego sposobu, aby przedłużyć błąd, otrzymasz ten sam brakujący stos (na Chromium41). –

+1

Czy możesz potwierdzić, z której przeglądarki korzystasz? Wydaje się, że działa także dla Chrome v42 https://jsfiddle.net/5e3kakqj/ – coder

+1

@coder na Chrome 42. Twój przykład działa, ale wersja Babel tego nie robi. – ssube

Odpowiedz

9

W skrócie, wyciągając przy użyciu kodu transpiled Babla działa tylko dla klas wbudowanych w określony sposób, a wiele rodzimy rzeczy nie wydają się tak zbudowane. Dokumenty Babel ostrzegają, że rozszerzenie wielu klas rodzimych nie działa poprawnie.

Można utworzyć klasę, która tworzy bufor właściwości "ręcznie", coś takiego:

class ErrorClass extends Error { 
    constructor (message) { 
    super(); 

    if (Error.hasOwnProperty('captureStackTrace')) 
     Error.captureStackTrace(this, this.constructor); 
    else 
     Object.defineProperty(this, 'stack', { 
      value: (new Error()).stack 
     }); 

    Object.defineProperty(this, 'message', { 
     value: message 
    }); 
    } 

} 

Następnie rozszerzenia tej klasy Zamiast:

class FooError extends ErrorClass { 
    constructor(message) { 
    super(message); 
    } 
} 

Dlaczego nie działa tak, jak można się spodziewać?

Jeśli spojrzeć na to, co jest transpiled, zobaczysz, że babel pierwszy przypisuje kopię super klasy prototypu do klasy sub, następnie podczas rozmowy new SubClass() ta funkcja nazywa się:

_get(Object.getPrototypeOf(FooError.prototype), "constructor", this).call(this, message) 

Gdzie _GET jest funkcją pomocnik wstrzykiwane do skryptu:

(function get(object, property, receiver) { 
    var desc = Object.getOwnPropertyDescriptor(object, property); 

    if (desc === undefined) { 
    var parent = Object.getPrototypeOf(object); 

    if (parent === null) { 
     return undefined; 
    } else { 
     return get(parent, property, receiver); 
    } 
    } else if ("value" in desc) { 
    return desc.value; 
    } else { 
    var getter = desc.get; 

    if (getter === undefined) { 
     return undefined; 
    } 

    return getter.call(receiver); 
    } 
}); 

to ma coś znajdzie deskryptor constructor właściwości klasy sub prototypu prototypu i starał się wywołać jej getter wi th nowa instancja podklasy jako kontekst, jeśli istnieje, lub zwróć jej wartość (if ("value" in desc)), w tym przypadku sam konstruktor Error. Nie przypisuje niczego do this z superukierunku, więc podczas gdy nowy obiekt ma odpowiedni prototyp, nie został skonstruowany tak, jak oczekujesz. Zasadniczo super wywołanie nic nie robi dla nowo skonstruowanego obiektu, po prostu tworzy nowy Error, który nie jest przypisany do niczego.

Jeśli użyjemy zdefiniowanego powyżej ErrorClass, będzie on przylegał do struktury klas zgodnie z oczekiwaniami Babel.

+0

Wydaje się to słuszne. Można rozszerzyć tylko niektóre obiekty natywne, używając natywnej składni. – ssube

+0

Ja (myślę) to zadziała poprawnie, gdy klasy ES2015 będą uruchamiane natywnie w przeglądarkach (w porównaniu do wersji ES5, ponieważ niektóre funkcje są niemożliwe do zobrazowania). – trusktr

Powiązane problemy