Bagaimana cara membuat Kesalahan khusus dalam JavaScript?

215

Untuk beberapa alasan, sepertinya delegasi konstruktor tidak berfungsi dalam cuplikan berikut:

function NotImplementedError() { 
  Error.apply(this, arguments); 
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");
console.log("The message is: '"+nie.message+"'")

Menjalankan ini memberi The message is: ''. Adakah ide mengapa, atau jika ada cara yang lebih baik untuk membuat Errorsubkelas baru ? Apakah ada masalah dengan konstruktor applyasli Erroryang saya tidak tahu?

cdleary
sumber
Apakah pernyataan NotImplementedError ini berfungsi setelah perubahan Anda? Saya berpikir bahwa agar ini berfungsi, Anda perlu mendefinisikan NotImplementedError.prototype.constructor secara eksplisit.
jayarjo
Lain kali, tolong hapus semua kode asing yang tidak diperlukan untuk menunjukkan masalah Anda. Juga, wtc adalah js.jar? Apakah itu perlu mereproduksi masalah?
BT
2
Mengedit pertanyaan ini sehingga dapat dipahami dalam 10 detik, bukan 10 menit
BT
Saya membuat perpustakaan warisan / kelas yang mewarisi dari jenis Kesalahan dengan benar: github.com/fresheneesz/proto
BT
1
jsfiddle untuk beberapa jawaban teratas.
Nate

Jawaban:

194

Perbarui kode Anda untuk menetapkan prototipe Anda ke Error.prototype dan instanceof dan karya Anda menegaskan.

function NotImplementedError(message) {
    this.name = "NotImplementedError";
    this.message = (message || "");
}
NotImplementedError.prototype = Error.prototype;

Namun, saya hanya akan membuang objek Anda sendiri dan hanya memeriksa properti namanya.

throw {name : "NotImplementedError", message : "too lazy to implement"}; 

Edit berdasarkan komentar

Setelah melihat komentar dan mencoba mengingat mengapa saya akan menetapkan prototipe, Error.prototypebukan new Error()seperti yang dilakukan Nicholas Zakas dalam artikelnya , saya membuat jsFiddle dengan kode di bawah ini:

function NotImplementedError(message) {
  this.name = "NotImplementedError";
  this.message = (message || "");
}
NotImplementedError.prototype = Error.prototype;

function NotImplementedError2(message) {
  this.message = (message || "");
}
NotImplementedError2.prototype = new Error();

try {
  var e = new NotImplementedError("NotImplementedError message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

try {
  var e = new NotImplementedError2("NotImplementedError2 message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError2 = " + (ex1 instanceof NotImplementedError2));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

Output konsol adalah ini.

undefined
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
Error
    at window.onload (http://fiddle.jshell.net/MwMEJ/show/:29:34)
ex1 instanceof NotImplementedError2 = true
ex1 instanceof Error = true
ex1.name = Error
ex1.message = NotImplementedError2 message

Ini mengkonfirmasi "masalah" yang saya temui adalah properti stack kesalahan adalah nomor baris tempat new Error()dibuat, dan bukan di mana throw eterjadi. Namun, itu mungkin lebih baik yang memiliki efek samping dari NotImplementedError.prototype.name = "NotImplementedError"garis yang mempengaruhi objek Kesalahan.

Juga, perhatikan NotImplementedError2, ketika saya tidak mengatur .namesecara eksplisit, itu sama dengan "Kesalahan". Namun, seperti yang disebutkan dalam komentar, karena versi itu menetapkan prototipe new Error(), saya dapat mengatur NotImplementedError2.prototype.name = "NotImplementedError2"dan menjadi OK.

Kevin Hakanson
sumber
45
Jawaban terbaik, tetapi mengambil Error.prototypelangsung mungkin bentuk yang buruk. Jika nanti Anda ingin menambahkan NotImplementedError.prototype.toStringobjek sekarang alias ke Error.prototype.toString- lebih baik dilakukan NotImplementedError.prototype = new Error().
cdleary
4
Saya masih sedikit tersesat dalam semua hal prototipe itu. Mengapa dalam contoh Anda, Anda menetapkan nama untuk this.name dan tidak ke NotImplementedError.prototype.name? Bisakah Anda menjawab tolong, ini penting untuk pemahaman saya :)
jayarjo
27
Menurut code.google.com/p/chromium/issues/detail?id=228909 subclass.prototype = new Error() adalah bentuk yang buruk. Anda seharusnya menggunakan subclass.prototype = Object.create(superclass.prototype)sebagai gantinya. Saya berharap ini dapat memperbaiki masalah stack-trace juga.
Gili
8
Trik sederhana untuk mendapatkan stacktrace yang bermakna adalah dengan menghasilkan kesalahan dalam konstruktor dan menyimpan tumpukan itu. Ini akan memberikan panggilan yang tepat stack + 1 baris untuk konstruktor (ini adalah hasil yang cocok):this.stack = new Error().stack;
Meredian
6
-1; ini salah. Melakukan NotImplementedError.prototype = Error.prototype;tidak membuat instanceofmemperlakukan NotImplementedErrorsebagai subclass dari Error, itu membuat instanceofmemperlakukan mereka sebagai kelas yang sama persis. Jika Anda menempelkan kode di atas ke konsol Anda dan mencoba new Error() instanceof NotImplementedErrorAnda akan mendapatkannya true, yang jelas salah.
Mark Amery
87

Semua jawaban di atas sangat mengerikan - sungguh. Bahkan yang memiliki 107 up! Jawaban sebenarnya ada di sini kawan:

Mewarisi dari objek Kesalahan - di mana properti pesan?

TL; DR:

A. Alasan messagetidak diatur adalah bahwa Errorini adalah fungsi yang mengembalikan objek kesalahan baru dan tidak memanipulasi thisdengan cara apa pun.

B. Cara untuk melakukan ini dengan benar adalah dengan mengembalikan hasil berlaku dari konstruktor, serta menetapkan prototipe dengan cara javascripty rumit yang biasa:

function MyError() {
    var temp = Error.apply(this, arguments);
    temp.name = this.name = 'MyError';
    this.message = temp.message;
    if(Object.defineProperty) {
        // getter for more optimizy goodness
        /*this.stack = */Object.defineProperty(this, 'stack', { 
            get: function() {
                return temp.stack
            },
            configurable: true // so you can change it if you want
        })
    } else {
        this.stack = temp.stack
    }
}
//inherit prototype using ECMAScript 5 (IE 9+)
MyError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: MyError,
        writable: true,
        configurable: true
    }
});

var myError = new MyError("message");
console.log("The message is: '" + myError.message + "'"); // The message is: 'message'
console.log(myError instanceof Error); // true
console.log(myError instanceof MyError); // true
console.log(myError.toString()); // MyError: message
console.log(myError.stack); // MyError: message \n 
// <stack trace ...>


 
//for EMCAScript 4 or ealier (IE 8 or ealier), inherit prototype this way instead of above code:
/*
var IntermediateInheritor = function() {};
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor();
*/

Anda mungkin dapat melakukan beberapa tipu daya untuk menghitung semua properti yang tidak dapat dihitung dari tmpKesalahan untuk mengaturnya daripada hanya mengatur secara eksplisit stackdan message, tetapi tipu daya tersebut tidak didukung yaitu <9

BT
sumber
2
Solusi ini juga berfungsi untuk membuat kesalahan kustom dengan kesalahan yang ada. Jika Anda menggunakan pustaka pihak ketiga dan ingin membungkus kesalahan yang ada dengan jenis kustom Anda sendiri, metode lain tidak berfungsi dengan benar. FYI, Anda bisa instantiate Kesalahan vanilla dengan mengirimkan mereka kesalahan yang ada.
Kyle Mueller
1
Anda seharusnya tidak berada return thisdi konstruktor.
Onur Yıldırım
13
Saya menyederhanakan dan meningkatkan pendekatan ini sedikit: jsbin.com/rolojuhuya/1/edit?js,console
Matt Kantor
3
@MattKantor mungkin menjawabnya? Saya pikir saya suka milikmu yang terbaik.
mpoisot
2
Alih-alih temp.name = this.name = 'MyError', Anda bisa melakukannya temp.name = this.name = this.constructor.name. Dengan begitu itu akan bekerja untuk subclass MyErrorjuga.
Jo Liss
45

Di ES2015, Anda dapat menggunakannya classuntuk melakukan ini dengan bersih:

class NotImplemented extends Error {
  constructor(message = "", ...args) {
    super(message, ...args);
    this.message = message + " has not yet been implemented.";
  }
}

Ini tidak mengubah global Errorprototipe, memungkinkan Anda untuk menyesuaikan message, namedan atribut lainnya, dan benar menangkap stack. Ini juga cukup mudah dibaca.

Tentu saja, Anda mungkin perlu menggunakan alat seperti babeljika kode Anda akan berjalan di browser yang lebih lama.

rattray
sumber
23

Jika ada yang ingin tahu tentang cara membuat kesalahan khusus dan mendapatkan jejak tumpukan:

function CustomError(message) {
  this.name = 'CustomError';
  this.message = message || '';
  var error = new Error(this.message);
  error.name = this.name;
  this.stack = error.stack;
}
CustomError.prototype = Object.create(Error.prototype);

try {
  throw new CustomError('foobar');
}
catch (e) {
  console.log('name:', e.name);
  console.log('message:', e.message);
  console.log('stack:', e.stack);
}
risto
sumber
7

Bagian standar ini dapat menjelaskan mengapa Error.applypanggilan tidak menginisialisasi objek:

15.11.1 Pembuat Kesalahan Disebut sebagai Fungsi

Ketika Kesalahan disebut sebagai fungsi alih-alih sebagai konstruktor, itu membuat dan menginisialisasi objek Kesalahan baru. Dengan demikian fungsi panggilan Kesalahan (...) setara dengan ekspresi penciptaan objek Kesalahan baru (...) dengan argumen yang sama.

Dalam hal ini Errorfungsi mungkin menentukan bahwa itu tidak disebut sebagai konstruktor, sehingga mengembalikan contoh kesalahan baru daripada menginisialisasi thisobjek.

Pengujian dengan kode berikut tampaknya menunjukkan bahwa inilah yang sebenarnya terjadi:

function NotImplementedError() { 
   var returned = Error.apply(this, arguments);
   console.log("returned.message = '" + returned.message + "'");
   console.log("this.message = '" + this.message + "'");
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");

Output berikut dihasilkan ketika ini dijalankan:

returned.message = 'some message'
this.message = ''
Dave
sumber
bagaimana ini bisa disimulasikan dengan kelas kesalahan khusus? Misalnya, bagaimana kelas kesalahan khusus saya dapat digunakan sebagai fungsi yang membuat instance dan sebagai konstruktor?
Lea Hayes
Tidak, ini tidak benar. Jika mengembalikan instance Kesalahan baru, maka properti pesannya akan berfungsi.
BT
@BT Bagaimana properti msg pada contoh baru mempengaruhi properti msg di thisdalam Error.apply(this, arguments);? Saya mengatakan panggilan untuk Kesalahan di sini adalah membangun objek baru, yang dibuang; tidak menginisialisasi objek yang sudah dibangun yang ditugaskan nie.
Dave
@BT Saya telah menambahkan beberapa kode contoh yang semoga memperjelas apa yang saya coba katakan.
Dave
@ Pernahkah saya salah memahami tujuan di sini, tetapi bukankah NotImplementedErrorimplementasi Anda mengembalikan returnedvariabel?
blong
7
function InvalidValueError(value, type) {
    this.message = "Expected `" + type.name + "`: " + value;
    var error = new Error(this.message);
    this.stack = error.stack;
}
InvalidValueError.prototype = new Error();
InvalidValueError.prototype.name = InvalidValueError.name;
InvalidValueError.prototype.constructor = InvalidValueError;
Pierre Voisin
sumber
3
Ini jawaban terbaik di sini. Itu succint dan pengecualian yang dibuat dengan cara ini akan berperilaku benar dalam semua situasi. Ini juga mempertahankan jejak tumpukan yang sangat penting dalam aplikasi non sepele. Saya hanya akan mengganti "prototype = new Error ()" dengan "prototype = Object.create (Error.prototype)". Untuk Node.js ada perpustakaan kecil yang melakukan ini untuk Anda: npmjs.com/package/node-custom-errors
Lukasz Korzybski
6

Saya punya masalah serupa dengan ini. Kesalahan saya perlu instanceofkeduanya Errordan NotImplemented, dan juga perlu menghasilkan backtrace yang koheren di konsol.

Solusi saya:

var NotImplemented = (function() {
  var NotImplemented, err;
  NotImplemented = (function() {
    function NotImplemented(message) {
      var err;
      err = new Error(message);
      err.name = "NotImplemented";
      this.message = err.message;
      if (err.stack) this.stack = err.stack;
    }
    return NotImplemented;
  })();
  err = new Error();
  err.name = "NotImplemented";
  NotImplemented.prototype = err;

  return NotImplemented;
}).call(this);

// TEST:
console.log("instanceof Error: " + (new NotImplemented() instanceof Error));
console.log("instanceof NotImplemented: " + (new NotImplemented() instanceofNotImplemented));
console.log("message: "+(new NotImplemented('I was too busy').message));
throw new NotImplemented("just didn't feel like it");

Hasil menjalankan dengan node.js:

instanceof Error: true
instanceof NotImplemented: true
message: I was too busy

/private/tmp/t.js:24
throw new NotImplemented("just didn't feel like it");
      ^
NotImplemented: just didn't feel like it
    at Error.NotImplemented (/Users/colin/projects/gems/jax/t.js:6:13)
    at Object.<anonymous> (/Users/colin/projects/gems/jax/t.js:24:7)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:487:10)
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

Kesalahan melewati ketiga kriteria saya, dan meskipun stackproperti tidak standar, didukung di sebagian besar browser yang lebih baru yang dapat diterima dalam kasus saya.

sinisterchipmunk
sumber
5

Menurut Joyent, Anda tidak boleh main-main dengan properti stack (yang saya lihat di banyak jawaban yang diberikan di sini), karena itu akan berdampak negatif pada kinerja. Inilah yang mereka katakan:

stack: secara umum, jangan main-main dengan ini. Jangan menambahnya. V8 hanya menghitungnya jika seseorang benar-benar membaca properti, yang meningkatkan kinerja secara dramatis untuk kesalahan yang dapat ditangani. Jika Anda membaca properti hanya untuk menambahnya, Anda akan membayar biayanya meskipun penelepon Anda tidak perlu tumpukan.

Saya suka dan ingin menyebutkan ide mereka untuk membungkus kesalahan asli yang merupakan pengganti yang bagus untuk melewati stack.

Jadi, inilah cara saya membuat kesalahan khusus, mengingat yang disebutkan di atas:

versi es5:

function RError(options) {
    options = options || {}; // eslint-disable-line no-param-reassign
    this.name = options.name;
    this.message = options.message;
    this.cause = options.cause;

    // capture stack (this property is supposed to be treated as private)
    this._err = new Error();

    // create an iterable chain
    this.chain = this.cause ? [this].concat(this.cause.chain) : [this];
}
RError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: RError,
        writable: true,
        configurable: true
    }
});

Object.defineProperty(RError.prototype, 'stack', {
    get: function stack() {
        return this.name + ': ' + this.message + '\n' + this._err.stack.split('\n').slice(2).join('\n');
    }
});

Object.defineProperty(RError.prototype, 'why', {
    get: function why() {
        var _why = this.name + ': ' + this.message;
        for (var i = 1; i < this.chain.length; i++) {
            var e = this.chain[i];
            _why += ' <- ' + e.name + ': ' + e.message;
        }
        return _why;
    }
});

// usage

function fail() {
    throw new RError({
        name: 'BAR',
        message: 'I messed up.'
    });
}

function failFurther() {
    try {
        fail();
    } catch (err) {
        throw new RError({
            name: 'FOO',
            message: 'Something went wrong.',
            cause: err
        });
    }
}

try {
    failFurther();
} catch (err) {
    console.error(err.why);
    console.error(err.stack);
    console.error(err.cause.stack);
}

versi es6:

class RError extends Error {
    constructor({name, message, cause}) {
        super();
        this.name = name;
        this.message = message;
        this.cause = cause;
    }
    [Symbol.iterator]() {
        let current = this;
        let done = false;
        const iterator = {
            next() {
                const val = current;
                if (done) {
                    return { value: val, done: true };
                }
                current = current.cause;
                if (!val.cause) {
                    done = true;
                }
                return { value: val, done: false };
            }
        };
        return iterator;
    }
    get why() {
        let _why = '';
        for (const e of this) {
            _why += `${_why.length ? ' <- ' : ''}${e.name}: ${e.message}`;
        }
        return _why;
    }
}

// usage

function fail() {
    throw new RError({
        name: 'BAR',
        message: 'I messed up.'
    });
}

function failFurther() {
    try {
        fail();
    } catch (err) {
        throw new RError({
            name: 'FOO',
            message: 'Something went wrong.',
            cause: err
        });
    }
}

try {
    failFurther();
} catch (err) {
    console.error(err.why);
    console.error(err.stack);
    console.error(err.cause.stack);
}

Saya telah memasukkan solusi saya ke dalam modul, ini dia: https://www.npmjs.com/package/rerror

borisdiakur
sumber
3

Saya suka melakukannya seperti ini:

  • Manfaatkan nama jadi toString () throws"{code}: {message}"
  • Kembalikan hal yang sama ke super sehingga tampak sama di stacktrace
  • Lampirkan kode error.codesebagai memeriksa / mem-parsing kode lebih baik dalam kode daripada memeriksa pesan, yang mungkin ingin Anda pelokalkan misalnya
  • Lampirkan pesan error.messagesebagai alternatiferror.toString()

class AppException extends Error {
  constructor(code, message) {
    const fullMsg = message ? `${code}: ${message}` : code;
    super(fullMsg);
    this.name = code;
    this.code = code;
    this.message = fullMsg;
  }
  
  toString() {
    return this.message;
  }
}

// Just a code
try {
  throw new AppException('FORBIDDEN');
} catch(e) {
  console.error(e);
  console.error(e.toString());
  console.log(e.code === 'FORBIDDEN');
}

// A code and a message
try {
  throw new AppException('FORBIDDEN', 'You don\'t have access to this page');
} catch(e) {
  console.error(e);
  console.error(e.toString());
  console.log(e.code === 'FORBIDDEN');
}

Dominic
sumber
2

Saya hanya perlu mengimplementasikan sesuatu seperti ini dan menemukan bahwa tumpukan hilang dalam implementasi kesalahan saya sendiri. Apa yang harus saya lakukan adalah membuat kesalahan dummy dan mengambil tumpukan dari itu:

My.Error = function (message, innerException) {
    var err = new Error();
    this.stack = err.stack; // IMPORTANT!
    this.name = "Error";
    this.message = message;
    this.innerException = innerException;
}
My.Error.prototype = new Error();
My.Error.prototype.constructor = My.Error;
My.Error.prototype.toString = function (includeStackTrace) {
    var msg = this.message;
    var e = this.innerException;
    while (e) {
        msg += " The details are:\n" + e.message;
        e = e.innerException;
    }
    if (includeStackTrace) {
        msg += "\n\nStack Trace:\n\n" + this.stack;
    }
    return msg;
}
Jules
sumber
Ini tidak mengatur pesan
BT
2

Saya menggunakan Pola Konstruktor untuk membuat objek kesalahan baru. Saya mendefinisikan rantai prototipe seperti Errorcontoh. Lihat referensi konstruktor MDN Error .

Anda dapat memeriksa cuplikan ini di intisari ini .

PENERAPAN

// Creates user-defined exceptions
var CustomError = (function() {
  'use strict';

  //constructor
  function CustomError() {
    //enforces 'new' instance
    if (!(this instanceof CustomError)) {
      return new CustomError(arguments);
    }
    var error,
      //handles the arguments object when is passed by enforcing a 'new' instance
      args = Array.apply(null, typeof arguments[0] === 'object' ? arguments[0] : arguments),
      message = args.shift() || 'An exception has occurred';

    //builds the message with multiple arguments
    if (~message.indexOf('}')) {
      args.forEach(function(arg, i) {
        message = message.replace(RegExp('\\{' + i + '}', 'g'), arg);
      });
    }

    //gets the exception stack
    error = new Error(message);
    //access to CustomError.prototype.name
    error.name = this.name;

    //set the properties of the instance
    //in order to resemble an Error instance
    Object.defineProperties(this, {
      stack: {
        enumerable: false,
        get: function() { return error.stack; }
      },
      message: {
        enumerable: false,
        value: message
      }
    });
  }

  // Creates the prototype and prevents the direct reference to Error.prototype;
  // Not used new Error() here because an exception would be raised here,
  // but we need to raise the exception when CustomError instance is created.
  CustomError.prototype = Object.create(Error.prototype, {
    //fixes the link to the constructor (ES5)
    constructor: setDescriptor(CustomError),
    name: setDescriptor('JSU Error')
  });

  function setDescriptor(value) {
    return {
      configurable: false,
      enumerable: false,
      writable: false,
      value: value
    };
  }

  //returns the constructor
  return CustomError;
}());

PEMAKAIAN

Konstruktor CustomError dapat menerima banyak argumen untuk membangun pesan, misalnya

var err1 = new CustomError("The url of file is required"),
    err2 = new CustomError("Invalid Date: {0}", +"date"),
    err3 = new CustomError("The length must be greater than {0}", 4),
    err4 = new CustomError("Properties .{0} and .{1} don't exist", "p1", "p2");

throw err4;

Dan inilah tampilan kesalahan khusus:

Rantai prototipe kesalahan khusus

jherax
sumber
Orang yang downvoted, apakah Anda memiliki argumen, atau alasan untuk memilih? atau hanya tidak mengerti maksud dalam kode.
jherax
Saya baru saja memperhatikan bahwa saya harus secara tidak sengaja mengklik tombol downvote saat menjelajah halaman ini tanpa disadari (kemungkinan menjelajah dari ponsel saya). Saya hanya memperhatikan hari ini saat menelusuri riwayat saya. Itu jelas tidak disengaja tetapi saya tidak bisa membatalkannya karena ini sedang masa tenggang. Anda memberikan jawaban yang informatif dan jelas tidak pantas menerimanya. Jika Anda mengedit, saya dengan senang hati akan membatalkan downvote. Maaf soal itu.
jschr
1

Konstruktor perlu seperti metode pabrik dan mengembalikan apa yang Anda inginkan. Jika Anda membutuhkan metode / properti tambahan, Anda dapat menambahkannya ke objek sebelum mengembalikannya.

function NotImplementedError(message) { return new Error("Not implemented", message); }

x = new NotImplementedError();

Meskipun saya tidak yakin mengapa Anda harus melakukan ini. Kenapa tidak pakai saja new Error...? Pengecualian khusus tidak benar-benar menambahkan banyak dalam JavaScript (atau mungkin bahasa yang tidak diketik).

pluckyglen
sumber
2
Anda harus mengaktifkan hierarki tipe Kesalahan atau nilai objek dalam JavaScript karena Anda hanya dapat menentukan satu blok tangkap. Dalam solusi Anda, (x instance NotImplementedError) salah, yang tidak dapat diterima dalam kasus saya.
cdleary
1

Ini diterapkan dengan baik di Cesium DeveloperError:

Dalam bentuknya yang disederhanakan:

var NotImplementedError = function(message) {
    this.name = 'NotImplementedError';
    this.message = message;
    this.stack = (new Error()).stack;
}

// Later on...

throw new NotImplementedError();
Aram Kocharyan
sumber
Ini berfungsi dengan baik, kecuali bahwa tumpukan akan berisi garis tambahan untuk konstruktor kesalahan, yang bisa menjadi masalah.
SystemParadox
Juga, tidak lulus error instanceof Errorujian, yang dapat membantu.
Lauren
1

Ini implementasi saya:

class HttpError extends Error {
  constructor(message, code = null, status = null, stack = null, name = null) {
    super();
    this.message = message;
    this.status = 500;

    this.name = name || this.constructor.name;
    this.code = code || `E_${this.name.toUpperCase()}`;
    this.stack = stack || null;
  }

  static fromObject(error) {
    if (error instanceof HttpError) {
      return error;
    }
    else {
      const { message, code, status, stack } = error;
      return new ServerError(message, code, status, stack, error.constructor.name);
    }
  }

  expose() {
    if (this instanceof ClientError) {
      return { ...this };
    }
    else {
      return {
        name: this.name,
        code: this.code,
        status: this.status,
      }
    }
  }
}

class ServerError extends HttpError {}

class ClientError extends HttpError { }

class IncorrectCredentials extends ClientError {
  constructor(...args) {
    super(...args);
    this.status = 400;
  }
}

class ResourceNotFound extends ClientError {
  constructor(...args) {
    super(...args);
    this.status = 404;
  }
}

Contoh penggunaan # 1:

app.use((req, res, next) => {
  try {
    invalidFunction();
  }
  catch (err) {
    const error = HttpError.fromObject(err);
    return res.status(error.status).send(error.expose());
  }
});

Contoh penggunaan # 2:

router.post('/api/auth', async (req, res) => {
  try {
    const isLogged = await User.logIn(req.body.username, req.body.password);

    if (!isLogged) {
      throw new IncorrectCredentials('Incorrect username or password');
    }
    else {
      return res.status(200).send({
        token,
      });
    }
  }
  catch (err) {
    const error = HttpError.fromObject(err);
    return res.status(error.status).send(error.expose());
  }
});
Rafal Enden
sumber
0

Dengan mengorbankan ketidakmampuan untuk digunakan instanceof, berikut ini mempertahankan jejak tumpukan asli dan tidak menggunakan trik non-standar.

// the function itself
var fixError = function(err, name) {
    err.name = name;
    return err;
}

// using the function
try {
    throw fixError(new Error('custom error message'), 'CustomError');
} catch (e) {
    if (e.name == 'CustomError')
        console.log('Wee! Custom Error! Msg:', e.message);
    else
        throw e; // unhandled. let it propagate upwards the call stack
}
Gima
sumber
yang harus Anda lakukan di sini untuk dapat menggunakan instanceof adalah melempar fixError baru, bukan hanya fixError
BT
@BT: Tidak dengan fixErrorfungsi di atas. Menambahkan newketika memanggil itu hanya akan membuat objek yang dibuang.
TJ Crowder
Oh saya kira saya maksud menggunakan "instanceof fixError" - tentu saja kemudian "instanceof Kesalahan" tidak akan berfungsi .. saya kira itu lebih buruk ..
BT
0

Alternatif lain, mungkin tidak bekerja di semua lingkungan. Pastikan itu bekerja di nodejs 0.8 Pendekatan ini menggunakan cara tidak standar dalam memodifikasi proto prop internal.

function myError(msg){ 
      var e = new Error(msg); 
      _this = this; 
      _this.__proto__.__proto__ = e;
}
Chandu
sumber
0

Jika Anda menggunakan Node / Chrome. Cuplikan berikut akan memberi Anda ekstensi yang memenuhi persyaratan berikut.

  • err instanceof Error
  • err instanceof CustomErrorType
  • console.log () kembali [CustomErrorType]ketika dibuat dengan pesan
  • console.log () kembali [CustomErrorType: message]ketika dibuat tanpa pesan
  • throw / stack memberikan informasi pada titik kesalahan itu dibuat.
  • Bekerja secara optimal di Node.JS, dan Chrome.
  • Akan memberikan contoh pemeriksaan di Chrome, Safari, Firefox dan IE 8+, tetapi tidak akan memiliki tumpukan yang valid di luar Chrome / Safari. Saya setuju dengan itu karena saya dapat men-debug di chrome, tetapi kode yang memerlukan jenis kesalahan spesifik masih akan berfungsi lintas browser. Jika Anda hanya perlu Node, Anda dapat dengan mudah menghapus ifpernyataan dan Anda siap melakukannya .

Potongan

var CustomErrorType = function(message) {
    if (Object.defineProperty) {
        Object.defineProperty(this, "message", {
            value : message || "",
            enumerable : false
        });
    } else {
        this.message = message;
    }

    if (Error.captureStackTrace) {
        Error.captureStackTrace(this, CustomErrorType);
    }
}

CustomErrorType.prototype = new Error();
CustomErrorType.prototype.name = "CustomErrorType";

Pemakaian

var err = new CustomErrorType("foo");

Keluaran

var err = new CustomErrorType("foo");
console.log(err);
console.log(err.stack);

[CustomErrorType: foo]
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

/errorTest.js:30
        throw err;
              ^
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3
Nukleon
sumber
0

Berikut ini berfungsi untuk saya yang diambil dari Kesalahan dokumentasi resmi Mozilla .

function NotImplementedError(message) {
    var instance = new Error(message);
    instance.name = 'NotImplementedError';

    Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
    if (Error.captureStackTrace) {
        Error.captureStackTrace(instance, NotImplementedError);
    }
    return instance;
}

NotImplementedError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: Error,
        enumerable: false,
        writable: true,
        configurable: true
    }
});
Zhunio
sumber
-1

Coba objek prototipe baru untuk setiap instance dari tipe kesalahan yang ditentukan pengguna. Hal ini memungkinkan instanceofpemeriksaan untuk berperilaku seperti biasa plus jenis dan pesan dilaporkan dengan benar di Firefox dan V8 (Chome, nodejs).

function NotImplementedError(message){
    if(NotImplementedError.innercall===undefined){
        NotImplementedError.innercall = true;
        NotImplementedError.prototype = new Error(message);
        NotImplementedError.prototype.name = "NotImplementedError";
        NotImplementedError.prototype.constructor = NotImplementedError;

        return new NotImplementedError(message);
    }
    delete NotImplementedError.innercall;
}

Perhatikan bahwa entri tambahan akan mendahului tumpukan yang benar.

Augustus Kling
sumber
Tidak bekerja Cobalah: var a = new NotImplementedError('a'), b = new NotImplementedError('b');. Sekarang a instanceof NotImplementedError == falsedanb instanceof NotImplementedError == true
jjrv
-1

Ini cara tercepat untuk melakukannya:

    let thisVar = false

    if (thisVar === false) {
            throw new Error("thisVar is false. It should be true.")
    }
jlhs
sumber
-3

cara yang lebih mudah. Anda bisa membuat objek Anda mewarisi dari objek Kesalahan. Contoh:

function NotImplementError(message)
{
    this.message = message;
    Error.call();
    Error.call(message);
} 

apa yang kita lakukan adalah menggunakan pemanggilan fungsi () yang memanggil konstruktor dari kelas Kesalahan sehingga pada dasarnya sama dengan menerapkan warisan kelas dalam bahasa berorientasi objek lainnya.

Paulo Enmanuel
sumber
-3

MDN memiliki contoh yang sangat baik :

try {
  throw new Error('Whoops!');
} catch (e) {
  console.log(e.name + ': ' + e.message);
}
Ronnie Royston
sumber