JavaScript'te nasıl özel bir Hata oluştururum?


215

Bazı nedenlerden dolayı, kurucu delegasyonu aşağıdaki snippet'te çalışmıyor gibi görünüyor:

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

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

Bunu çalıştırmak verir The message is: ''. Neden olduğu veya yeni bir Erroralt sınıf oluşturmanın daha iyi bir yolu olup olmadığı hakkında herhangi bir fikir var mı? Bilmediğim applyyerli kurucuya bir sorun Errorvar mı?


Nie instanceof NotImplementedError iddiası değişikliklerinizden sonra çalışıyor mu? Bunun çalışması için NotImplementedError.prototype.constructor'ı açıkça tanımlamanız gerektiğini düşündüm.
jayarjo

Bir dahaki sefere, sorununuzu göstermek için gerekli olmayan tüm gereksiz kodları göz ardı edin. Ayrıca, wtc js.jar? Sorunu yeniden üretmek için buna gerek var mı?
BT

2
Bu soruyu 10 dakika yerine 10 saniyede anlaşılabilir şekilde düzenledi
BT

Hata türlerinden düzgün bir şekilde miras alan bir miras / sınıf kütüphanesi oluşturdum: github.com/fresheneesz/proto
BT

1
en iyi cevaplar için jsfiddle .
Nate

Yanıtlar:


194

Prototipinizi Error.prototype'e ve instanceof ve assilen'lerinize atamak için kodunuzu güncelleyin.

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

Ancak, sadece kendi nesne atmak ve sadece name özelliği kontrol ediyorum.

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

Yorumlara göre düzenleme

Yorumlarını inceleyerek ve ben prototip atamak neden hatırlamaya çalışarak sonra Error.prototypeyerine new Error()Nicholas Zakas onun yaptığı gibi makalesinde , ben oluşturulan jsFiddle Aşağıdaki kod ile:

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

Konsol çıkışı buydu.

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

Bu, ben hata "yığın" özelliği hata oluştu new Error()nerede throw eoluştuğu değil, oluşturulan satır numarası olduğunu doğruladı . Bununla birlikte, NotImplementedError.prototype.name = "NotImplementedError"Error nesnesini etkileyen bir çizginin yan etkisine sahip olmak daha iyi olabilir .

Ayrıca, açıkça, ben açıkça NotImplementedError2ayarlanmadığında, .name"Hata" eşittir dikkat edin. Ancak, yorumlarda belirtildiği gibi, bu sürüm prototipi new Error()ayarladığından, ayarlayabilir NotImplementedError2.prototype.name = "NotImplementedError2"ve iyi olabilirim.


45
En iyi cevap, ancak Error.prototypedoğrudan almak muhtemelen kötü bir formdur. Daha sonra bir NotImplementedError.prototype.toStringnesne eklemek istiyorsanız şimdi takma adlar Error.prototype.toString- yapmak daha iyi NotImplementedError.prototype = new Error().
cdleary

4
Tüm bu prototip şeylerde hala biraz kayboldum. Örneğinizde neden NotImplementedError.prototype.name'ye değil, bu.name'ye ad atasınız? Lütfen cevap verebilir misin, bu benim anlayışım için çok önemli :)
jayarjo 9:11

27
Göre code.google.com/p/chromium/issues/detail?id=228909 subclass.prototype = new Error() kötü şeklidir. Bunun subclass.prototype = Object.create(superclass.prototype)yerine kullanmanız gerekiyor . Ben de yığın izleme sorunu giderebilir umuyoruz.
Gili

8
Anlamlı stacktrace almak için basit hile yapıcı içinde hata oluşturmak ve onun yığını kaydetmek. Yapıcı için uygun çağrı yığını + 1 hattı verecektir (bu uygun bir ödeme):this.stack = new Error().stack;
Meredian

6
1; Bu yanlış. Yapma NotImplementedError.prototype = Error.prototype;yapmaz instanceoftedavi NotImplementedErrorbir şekilde alt sınıf arasında Error, yapar instanceofaynı sınıf olarak muamele onları. Yukarıdaki kodu konsolunuza yapıştırır ve new Error() instanceof NotImplementedErroralırsanız true, bu kesinlikle yanlıştır.
Mark Amery

87

Yukarıdaki cevapların hepsi korkunç korkunç - gerçekten. 107 ups ile bile! Asıl cevap burada:

Error nesnesinden devralma - message özelliği nerede?

TL; DR:

A. nedeni messageseti olmasıdır olmak değildir Error, yeni bir hata nesnesi döndüren ve bir işlevdir değil manipüle thishiçbir şekilde.

B. Bu hakkı yapmanın yolu, yapıcıdan uygulamanın sonucunu döndürmek ve prototipi her zamanki karmaşık javascripty tarzında ayarlamaktır:

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

Muhtemelen tmpyalnızca açıkça ayarlamak yerine onları ayarlamak için Hatanın tüm numaralandırılamayan özelliklerini numaralandırmak için bazı hile yapabilirsiniz stackve messageancak hile yani <9


2
Bu çözüm, varolan bir hatayla özel bir hatayı somutlaştırmak için de çalışır. Üçüncü taraf bir kitaplık kullanıyorsanız ve mevcut bir hatayı kendi özel türünüzle sarmak istiyorsanız, diğer yöntemler düzgün çalışmaz. Bilginize, vanilya hatalarını mevcut bir hatayı ileterek başlatabilirsiniz.
Kyle Mueller

1
bir kurucuda olmamalısınız return this.
Onur Yıldırım

13
Bu yaklaşımı biraz basitleştirdim ve geliştirdim: jsbin.com/rolojuhuya/1/edit?js,console
Matt Kantor

3
@MattKantor belki de bir cevap mı? Ben seninkini en çok sevdiğimi düşünüyorum.
mpoisot

2
Bunun yerine temp.name = this.name = 'MyError', yapabilirsiniz temp.name = this.name = this.constructor.name. Bu şekilde alt sınıfları için de işe yarayacaktır MyError.
Jo Liss

45

ES2015'te classbunu temiz bir şekilde yapmak için kullanabilirsiniz :

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

Bu, küresel değiştirmez Errorprototipi, özelleştirmek izin verir message, nameve diğer özellikleridir ve düzgün yığını yakalar. Ayrıca oldukça okunabilir.

Elbette, babelkodunuzun eski tarayıcılarda çalışıp çalışmayacağı gibi bir araç kullanmanız gerekebilir .


23

Birisi nasıl özel bir hata oluşturulacağını ve yığın izlemesini nasıl alacağını merak ederse :

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

7

Standardın bu bölümü, Error.applyçağrının neden nesneyi başlatmadığını açıklayabilir :

15.11.1 İşlev Olarak Çağrılan Hata Yapıcısı

Hata yapıcı olarak değil, işlev olarak çağrıldığında, yeni bir Error nesnesi oluşturur ve başlatır. Böylece Error (...) fonksiyon çağrısı, aynı argümanlara sahip yeni Error (...) nesne oluşturma ifadesine eşdeğerdir.

Bu durumda Errorişlev, büyük olasılıkla yapıcı olarak çağrılmadığını belirler, bu nedenle thisnesneyi başlatmak yerine yeni bir Error örneği döndürür .

Aşağıdaki kodla test etmek, bunun gerçekte ne olduğunu gösteriyor:

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

Bu çalıştırıldığında aşağıdaki çıktı oluşturulur:

returned.message = 'some message'
this.message = ''

bu özel bir hata sınıfıyla nasıl simüle edilebilir? Örneğin, özel hata sınıfım hem örnek oluşturan bir işlev hem de bir oluşturucu olarak nasıl kullanılabilir?
Lea Hayes

Hayır, bu doğru değil. Yeni bir Error örneği döndürürse, msg özelliği işe yarayacaktır.
BT

@BT Nasıl yeni örneğinde msg mülkiyet üzerinde msg özelliğini etkiler thisde Error.apply(this, arguments);? Ben burada Hata çağrısı atılan yeni bir nesne inşa olduğunu söylüyorum; atanmış olan nesnenin başlatılmaması nie.
Dave

@BT Umarım söylemeye çalıştığım şeyi netleştiren bir örnek kod ekledim.
Dave

@Dave burada amacı yanlış anlamış olabilirim, ancak NotImplementedErroruygulamanız returneddeğişkeni döndürmemeli mi?
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;

3
Buradaki en iyi cevap bu. Özlüdür ve bu şekilde oluşturulan istisna her durumda doğru davranacaktır. Ayrıca önemsiz olmayan uygulamalarda çok önemli olan yığın izini de korur. Yalnızca "prototype = new Error ()" yerine "prototype = Object.create (Error.prototype)" ifadesini koyarım. Node.js için bunu sizin için yapan küçük bir kütüphane var: npmjs.com/package/node-custom-errors
Lukasz Korzybski 14:15

6

Buna benzer bir sorunum vardı. Benim hata ihtiyaçları bir olmak instanceofhem Errorve NotImplementedve aynı zamanda konsolda tutarlı geri izleme üretmek gerekiyor.

Çözümüm:

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

Node.js ile çalışmanın sonucu:

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)

Hata, ölçütlerimin stacküçünü de aşıyor ve özellik standart olmamasına rağmen, benim durumumda kabul edilebilir olan en yeni tarayıcılarda destekleniyor .


5

Joyent'e göre (burada verilen cevapların çoğunda gördüğüm) stack özelliği ile uğraşmamalısınız , çünkü performans üzerinde olumsuz bir etkisi olacaktır. İşte söyledikleri:

yığın: genellikle, bununla uğraşma. Arttırmayın bile. V8, yalnızca birisi özelliği gerçekten okuyorsa hesaplanır, bu da işlenebilir hatalar için performansı önemli ölçüde artırır. Mülkü sadece artırmak için okursanız, arayanınız yığına ihtiyaç duymasa bile maliyeti ödersiniz.

Seviyorum ve yığın üzerinden geçmek için güzel bir yedek olan orijinal hatayı sarma fikrinden bahsetmek istiyorum .

Yukarıda belirtilenleri dikkate alarak özel bir hatayı nasıl oluşturacağım:

es5 sürümü:

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

es6 sürümü:

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

Çözümümü bir modüle koydum, işte burada: https://www.npmjs.com/package/rerror


3

Ben böyle yapmak istiyorum:

  • ToString () ifadeleri için adı kullanın"{code}: {message}"
  • Aynı şeyi süper haline getirin, böylece yığın izinde aynı görünür
  • Kodu error.codekontrol etmek / ayrıştırmak için kodu, örneğin yerelleştirmek isteyebileceğiniz bir iletiyi kontrol etmekten daha iyidir.
  • İletisine error.messagealternatif olarak ekleerror.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');
}


2

Sadece böyle bir şey uygulamak zorunda kaldı ve kendi hata uygulamamda yığını kayboldu bulundu. Ne yapmak zorunda bir kukla hata oluşturmak ve ondan yığını almak oldu:

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

Bu mesajı ayarlamaz
BT

2

Yeni hata nesnesini oluşturmak için Oluşturucu Deseni'ni kullandım. Örnek olarak prototip zincirini tanımladım Error. MDN Hatası yapıcı başvurusuna bakın.

Bu pasajı bu özden kontrol edebilirsiniz .

UYGULAMA

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

KULLANIM

CustomError yapıcısı mesajı oluşturmak için birçok argüman alabilir, örn.

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;

Özel hata şu şekilde görünür:

Özel hata prototip zinciri


Aşağı iten kişi, argümanlarınız mı var ya da oy kullanma nedeniniz mi var? ya da koddaki niyeti anlamıyor.
jherax

Sadece fark etmeden bu sayfaya göz atarken (telefonumdan göz atma) yanlışlıkla aşağı oy düğmesine tıklamam gerektiğini fark ettim. Bugün sadece geçmişime göz atarken fark ettim. Kesinlikle kasıtlı değildi ama lütuf dönemi boyunca olduğu gibi geri alamıyorum. Bilgilendirici bir cevap verdiniz ve kesinlikle bunu hak etmiyorsunuz. Bir düzenleme yaparsanız, aşağı oyu mutlu bir şekilde geri alacağım. Bunun için üzgünüm.
jschr

1

Yapıcı bir fabrika yöntemi gibi olmalı ve istediğinizi döndürmelidir. Ek yöntemlere / özelliklere ihtiyacınız varsa, döndürmeden önce bunları nesneye ekleyebilirsiniz.

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

x = new NotImplementedError();

Yine de bunu neden yapmanız gerektiğinden emin değilim. Neden sadece kullanmıyorsunuz new Error...? Özel istisnalar, JavaScript'te (veya muhtemelen türsüz bir dilde) fazla bir şey eklemez.


2
Yalnızca tek bir yakalama bloğu belirtebileceğiniz için JavaScript'te Hata türü hiyerarşisini veya nesne değerini açmanız gerekir. Çözümünüzde, (x instanceof NotImplementedError) yanlış, bu benim durumumda kabul edilemez.
cdleary

1

Bu Cesium DeveloperError'da güzel bir şekilde uygulanır:

Basitleştirilmiş biçimde:

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

// Later on...

throw new NotImplementedError();

Yığın, hata oluşturucu için sorun yaratabilecek fazladan bir satır içermesi dışında bu harika çalışır.
SystemParadox

Ayrıca, error instanceof Errortesti geçemez , bu da yardımcı olabilir.
Lauren

1

Bu benim uygulamam:

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

Örnek kullanım # 1:

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

Örnek kullanım # 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());
  }
});

0

Kullanılamama pahasına instanceof, aşağıdakiler orijinal yığın izini korur ve standart olmayan hileler kullanmaz.

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

instanceof'i kullanabilmek için burada yapmanız gereken tek şey sadece fixError yerine yeni fixError atmak
BT

@BT: fixErrorYukarıdaki işlevle değil . Bir newçağrıyı eklediğinizde, atılan bir nesne oluşturulur.
TJ Crowder

Oh sanırım ben "instanceof fixError" - demek istediğim o zaman "instanceof Error" işe yaramaz .. sanırım bu daha kötü ..
BT

0

Başka bir alternatif, tüm ortamlarda çalışmayabilir. En az 0.8'de çalıştığından emin olabilir. 0.8 Bu yaklaşım, dahili proto pervaneyi değiştirmenin standart olmayan bir yolunu kullanır.

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

0

Düğüm / Chrome kullanıyorsanız. Aşağıdaki snippet size aşağıdaki gereksinimleri karşılayan bir uzantı sağlayacaktır.

  • err instanceof Error
  • err instanceof CustomErrorType
  • console.log () [CustomErrorType]bir mesajla oluşturulduğunda geri döner
  • console.log () mesajsız [CustomErrorType: message]oluşturulduğunda geri döner
  • throw / stack, hatanın oluşturulduğu noktada bilgi sağlar.
  • Node.JS ve Chrome'da en iyi şekilde çalışır.
  • Chrome, Safari, Firefox ve IE 8+ sürümlerinde anında kontroller geçecek, ancak Chrome / Safari dışında geçerli bir yığını olmayacak. Chrome'da hata ayıklayabildiğim için sorun yok, ancak belirli hata türlerini gerektiren kod yine de çapraz tarayıcı işlevi görecek. Düğüme ihtiyacınız varsa, sadece ififadeleri kolayca kaldırabilirsiniz ve gitmekte fayda var .

Pasaj

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

kullanım

var err = new CustomErrorType("foo");

Çıktı

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

0

Aşağıdakiler benim için resmi Mozilla dokümantasyon hatasından alınmıştır .

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

-1

Kullanıcı tanımlı hata türünün her örneği için yeni bir prototip nesnesi deneyin. Bu veriyor instanceofkontroller doğru Firefox ve V8 (Chome, nodejs) bildirildi zamanki artı tipi ve mesaj olarak davranmaya.

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

Ek bir girişin, aksi takdirde doğru yığının önüne geçeceğini unutmayın.


Çalışmıyor. Deneyin: var a = new NotImplementedError('a'), b = new NotImplementedError('b');. Şimdi a instanceof NotImplementedError == falseveb instanceof NotImplementedError == true
jjrv

-1

Bunu yapmanın en hızlı yolu:

    let thisVar = false

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

-3

daha kolay bir yol. Nesnenin Error nesnesinden devralmasını sağlayabilirsiniz. Misal:

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

yaptığımız şey, Error sınıfının yapıcısını çağıran call call () işlevini kullanmaktır, bu nedenle temel olarak diğer nesne yönelimli dillerin bir sınıf mirasını uygulamakla aynı şeydir.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.