Làm cách nào để tạo Lỗi tùy chỉnh trong JavaScript?


214

Vì một số lý do, có vẻ như ủy quyền của nhà xây dựng không hoạt động trong đoạn mã sau:

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

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

Chạy này cho The message is: ''. Bất kỳ ý tưởng nào về lý do tại sao, hoặc nếu có một cách tốt hơn để tạo một Errorlớp con mới ? Có vấn đề gì với applying với nhà Errorxây dựng bản địa mà tôi không biết?


Liệu khẳng định nie của NotImcellenceedError có hoạt động sau khi bạn thay đổi không? Tôi nghĩ rằng để làm việc này, bạn cần xác định rõ ràng NotIm HiệnedError.prototype.constructor.
jayarjo

Lần tới, vui lòng xé tất cả các mã không liên quan không cần thiết để chứng minh vấn đề của bạn. Ngoài ra, wtc là js.jar? Có cần thiết để tái tạo vấn đề?
BT

2
Chỉnh sửa câu hỏi này sao cho dễ hiểu trong 10 giây thay vì 10 phút
BT

Tôi đã tạo thư viện kế thừa / lớp kế thừa từ các loại Lỗi chính xác: github.com/fresheneesz/proto
BT

1
jsfiddle cho một vài câu trả lời hàng đầu.
Nate

Câu trả lời:


193

Cập nhật mã của bạn để gán nguyên mẫu của bạn cho Error.prototype và thể hiện và các xác nhận của bạn hoạt động.

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

Tuy nhiên, tôi sẽ chỉ ném đối tượng của riêng bạn và chỉ kiểm tra thuộc tính tên.

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

Chỉnh sửa dựa trên ý kiến

Sau khi xem các bình luận và cố gắng nhớ tại sao tôi lại gán nguyên mẫu Error.prototypethay vì new Error()như Nicholas Zakas đã làm trong bài viết của mình , tôi đã tạo ra một jsFiddle với mã dưới đây:

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

Đầu ra giao diện điều khiển là thế này.

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

Điều này xác nhận "vấn đề" mà tôi gặp phải là thuộc tính ngăn xếp của lỗi là số dòng new Error()được tạo và không phải là nơi throw exảy ra. Tuy nhiên, điều đó có thể tốt hơn khi có tác dụng phụ của một NotImplementedError.prototype.name = "NotImplementedError"dòng ảnh hưởng đến đối tượng Lỗi.

Ngoài ra, lưu ý với NotImplementedError2, khi tôi không đặt .namerõ ràng, nó bằng "Lỗi". Tuy nhiên, như đã đề cập trong các bình luận, vì phiên bản đó đặt nguyên mẫu new Error(), tôi có thể đặt NotImplementedError2.prototype.name = "NotImplementedError2"và ổn.


45
Câu trả lời tốt nhất, nhưng lấy Error.prototypetrực tiếp có lẽ là hình thức xấu. Nếu sau này bạn muốn thêm một NotImplementedError.prototype.toStringđối tượng bây giờ bí danh Error.prototype.toString- tốt hơn để làm NotImplementedError.prototype = new Error().
cdleary

4
Tôi vẫn còn một chút lạc lõng trong tất cả những thứ nguyên mẫu đó. Tại sao trong ví dụ của bạn, bạn chỉ định tên cho this.name mà không phải là NotImcellenceedError.prototype.name? Bạn có thể trả lời không, nó rất quan trọng đối với sự hiểu biết của tôi :)
jayarjo

27
Theo code.google.com/p/chromium/issues/detail?id=228909 subclass.prototype = new Error() là hình thức xấu. Bạn có nghĩa vụ phải sử dụng subclass.prototype = Object.create(superclass.prototype)thay thế. Tôi hy vọng nó cũng có thể khắc phục vấn đề theo dõi stack.
Gili

8
Thủ thuật đơn giản để có được stacktrace có ý nghĩa là tạo ra lỗi trong hàm tạo và lưu stack đó. Nó sẽ cung cấp ngăn xếp cuộc gọi thích hợp + 1 dòng cho nhà xây dựng (đó là một khoản thanh toán phù hợp):this.stack = new Error().stack;
Meredian

6
-1; cái này sai. Làm NotImplementedError.prototype = Error.prototype;không làm cho instanceofđiều trị NotImplementedErrornhư một lớp con của Error, nó làm cho instanceofđiều trị chúng như cùng lớp chính xác. Nếu bạn dán đoạn mã trên vào bảng điều khiển của mình và thử, new Error() instanceof NotImplementedErrorbạn sẽ nhận được true, điều này rõ ràng là sai.
Đánh dấu Amery

87

Tất cả các câu trả lời trên là khủng khiếp khủng khiếp - thực sự. Ngay cả một với 107 up! Câu trả lời thực sự là đây các bạn:

Kế thừa từ đối tượng Error - thuộc tính thông báo ở đâu?

TL; DR:

A. Lý do messagekhông được đặt ra là đó Errorlà một hàm trả về một đối tượng Lỗi mới và không thao tác thistheo bất kỳ cách nào.

B. Cách để thực hiện quyền này là trả về kết quả của ứng dụng từ hàm tạo, cũng như đặt nguyên mẫu theo cách javascripty phức tạp thông thường:

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

Bạn có thể có thể thực hiện một số thủ thuật để liệt kê tất cả các thuộc tính không thể đếm được của tmpLỗi để đặt chúng thay vì chỉ cài đặt rõ ràng stackmessage, nhưng thủ thuật không được hỗ trợ trong ví dụ <9


2
Giải pháp này cũng hoạt động để khởi tạo một lỗi tùy chỉnh với một lỗi hiện có. Nếu bạn đang sử dụng thư viện của bên thứ ba và muốn xử lý một lỗi hiện có với loại tùy chỉnh của riêng bạn, các phương pháp khác không hoạt động đúng. FYI, bạn có thể khởi tạo lỗi vanilla bằng cách chuyển cho chúng một lỗi hiện có.
Kyle Mueller

1
bạn không nên return thistrong một nhà xây dựng.
Onur Yıldırım

13
Tôi đơn giản hóa và cải thiện phương pháp này một chút: jsbin.com/rolojuhuya/1/edit?js,console
Matt Kantor

3
@MattKantor có lẽ làm cho câu trả lời? Tôi nghĩ rằng tôi thích của bạn tốt nhất.
mpoisot

2
Thay vì temp.name = this.name = 'MyError', bạn có thể làm temp.name = this.name = this.constructor.name. Bằng cách đó, nó sẽ làm việc cho các lớp con MyErrorlà tốt.
Jo Liss

45

Trong ES2015, bạn có thể sử dụng classđể thực hiện việc này một cách sạch sẽ:

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

Điều này không thay đổi toàn cầu Errornguyên mẫu, cho phép bạn tùy chỉnh message, namevà các thuộc tính khác, và chụp đúng stack. Nó cũng khá dễ đọc.

Tất nhiên, bạn có thể cần sử dụng một công cụ như babelnếu mã của bạn sẽ chạy trên các trình duyệt cũ hơn.


23

Nếu có ai tò mò về cách tạo lỗi tùy chỉnh theo dõi ngăn xếp:

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

Phần này của tiêu chuẩn có thể giải thích tại sao Error.applycuộc gọi không khởi tạo đối tượng:

15.11.1 Trình xây dựng lỗi được gọi là hàm

Khi Lỗi được gọi là hàm chứ không phải là hàm tạo, nó sẽ tạo và khởi tạo một đối tượng Lỗi mới. Do đó, hàm gọi Lỗi (...) tương đương với biểu thức tạo đối tượng Lỗi mới (...) có cùng đối số.

Trong trường hợp này, Errorhàm có thể xác định rằng nó không được gọi là hàm tạo, do đó, nó trả về một thể hiện Lỗi mới thay vì khởi tạo thisđối tượng.

Thử nghiệm với đoạn mã sau dường như chứng minh rằng đây thực tế là những gì đang xảy ra:

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

Đầu ra sau đây được tạo khi chạy này:

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

Làm thế nào điều này có thể được mô phỏng với một lớp lỗi tùy chỉnh? Ví dụ, làm thế nào lớp lỗi tùy chỉnh của tôi có thể được sử dụng như là một hàm tạo ra một thể hiện và như là một hàm tạo?
Lea Hayes

Không, đây không phải là sự thật. Nếu nó trả về một trường hợp Lỗi mới, thì thuộc tính thông báo của anh ta sẽ hoạt động.
BT

@BT Làm thế nào để sở hữu msg trên các trường hợp mới ảnh hưởng đến tài sản msg trên thistrong Error.apply(this, arguments);? Tôi đang nói rằng lệnh gọi Lỗi ở đây đang xây dựng một đối tượng mới, bị vứt đi; không khởi tạo đối tượng đã được xây dựng được gán cho nie.
Dave

@BT Tôi đã thêm một số mã ví dụ hy vọng sẽ làm rõ hơn những gì tôi đang cố gắng nói.
Dave

@ Tôi có thể đã hiểu nhầm mục đích ở đây, nhưng NotImplementedErrorviệc triển khai của bạn không trả về returnedbiến?
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
Đây là câu trả lời tốt nhất ở đây. Đó là succint và ngoại lệ được tạo ra theo cách này sẽ hành xử chính xác trong mọi tình huống. Nó cũng bảo tồn dấu vết ngăn xếp rất quan trọng trong các ứng dụng không tầm thường. Tôi sẽ chỉ thay thế "nguyên mẫu = new Error ()" bằng "nguyên mẫu = Object.create (Error.prototype)". Đối với Node.js, có một thư viện nhỏ thực hiện điều này cho bạn: npmjs.com/package/node-custom-errors
Lukasz Korzybski

6

Tôi đã có một vấn đề tương tự như thế này. Nhu cầu lỗi của tôi là một instanceofcả ErrorNotImplemented, và nó cũng cần phải tạo ra một vết lùi mạch lạc trong giao diện điều khiển.

Giải pháp của tôi:

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

Kết quả của việc chạy với 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)

Lỗi vượt qua cả 3 tiêu chí của tôi và mặc dù thuộc stacktính không đạt tiêu chuẩn, nhưng nó được hỗ trợ trong hầu hết các trình duyệt mới hơn có thể chấp nhận được trong trường hợp của tôi.


5

Tham gia vào Joyent bạn không nên lộn xộn với thuộc tính stack (mà tôi thấy trong rất nhiều câu trả lời được đưa ra ở đây), bởi vì nó sẽ có tác động tiêu cực đến hiệu suất. Đây là những gì họ nói:

ngăn xếp: nói chung, đừng lộn xộn với điều này. Đừng thậm chí làm tăng nó. V8 chỉ tính toán nó nếu ai đó thực sự đọc tài sản, giúp cải thiện hiệu suất đáng kể cho các lỗi có thể xử lý được. Nếu bạn đọc tài sản chỉ để gia tăng tài sản, cuối cùng bạn sẽ phải trả chi phí ngay cả khi người gọi của bạn không cần đến ngăn xếp.

Tôi muốn và muốn đề cập đến ý tưởng của họ về việc gói lỗi ban đầu , đây là một sự thay thế tốt đẹp cho việc chuyển lên ngăn xếp.

Vì vậy, đây là cách tôi tạo một lỗi tùy chỉnh, xem xét các đề cập ở trên:

phiên bản 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);
}

phiên bản 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);
}

Tôi đã đưa giải pháp của mình vào một mô-đun, đây là: https://www.npmjs.com/package/rerror


3

Tôi thích làm như thế này:

  • Sử dụng tên để ném toString ()"{code}: {message}"
  • Trả lại điều tương tự cho siêu để nó xuất hiện giống nhau trong stacktrace
  • Đính kèm mã để error.codekiểm tra / phân tích mã là mã tốt hơn so với kiểm tra thư, ví dụ bạn có thể muốn bản địa hóa
  • Đính kèm tin nhắn để error.messagethay thế choerror.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

Tôi chỉ phải thực hiện một cái gì đó như thế này và thấy rằng ngăn xếp bị mất trong quá trình thực hiện lỗi của riêng tôi. Những gì tôi phải làm là tạo ra một lỗi giả và lấy stack từ đó:

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

Điều này không đặt thông báo
BT

2

Tôi đã sử dụng Mẫu xây dựng để tạo đối tượng lỗi mới. Tôi đã định nghĩa chuỗi nguyên mẫu như một Errorví dụ. Xem tham chiếu hàm tạo MDN Error .

Bạn có thể kiểm tra đoạn trích này trên ý chính này .

THỰC HIỆN

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

SỬ DỤNG

Hàm tạo CustomError có thể nhận được nhiều đối số để tạo thông báo, ví dụ:

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;

Và đây là lỗi tùy chỉnh trông như thế nào:

Chuỗi nguyên mẫu lỗi tùy chỉnh


Một trong những người đã đánh giá thấp, bạn có tranh luận, hoặc một lý do để bỏ phiếu không? hoặc chỉ không hiểu ý định trong mã.
jherax

Tôi chỉ nhận thấy rằng tôi đã vô tình nhấp vào nút downvote trong khi duyệt trang này mà không nhận ra (có thể duyệt từ điện thoại của tôi). Tôi chỉ nhận thấy ngày hôm nay trong khi duyệt lịch sử của tôi. Đó chắc chắn không phải là cố ý nhưng tôi không thể hoàn tác nó vì đã qua thời gian ân hạn. Bạn đã cung cấp một câu trả lời thông tin và chắc chắn không xứng đáng. Nếu bạn thực hiện chỉnh sửa, tôi sẽ vui vẻ hoàn tác downvote. Xin lỗi vì điều đó.
jschr

1

Hàm tạo cần giống như một phương thức xuất xưởng và trả về những gì bạn muốn. Nếu bạn cần các phương thức / thuộc tính bổ sung, bạn có thể thêm chúng vào đối tượng trước khi trả lại nó.

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

x = new NotImplementedError();

Mặc dù tôi không chắc tại sao bạn cần phải làm điều này. Tại sao không chỉ sử dụng new Error...? Các trường hợp ngoại lệ tùy chỉnh không thực sự bổ sung nhiều trong JavaScript (hoặc có thể là bất kỳ ngôn ngữ nào chưa được kiểm tra).


2
Bạn phải bật phân cấp loại lỗi hoặc giá trị đối tượng trong JavaScript vì bạn chỉ có thể chỉ định một khối bắt duy nhất. Trong giải pháp của bạn, (x instanceof NotImcellenceedError) là sai, không thể chấp nhận được trong trường hợp của tôi.
cdleary

1

Điều này được triển khai độc đáo trong Caesium DeveloperError:

Ở dạng đơn giản hóa:

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

// Later on...

throw new NotImplementedError();

Điều này hoạt động rất tốt, ngoại trừ ngăn xếp sẽ chứa một dòng bổ sung cho hàm tạo lỗi, đây có thể là một vấn đề.
SystemParadox

Ngoài ra, không vượt qua error instanceof Errorbài kiểm tra, có thể hữu ích.
Lauren

1

Đây là triển khai của tôi:

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

Ví dụ sử dụng # 1:

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

Ví dụ sử dụng # 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

Với chi phí không thể sử dụng instanceof, phần sau đây giữ nguyên dấu vết ngăn xếp ban đầu và không sử dụng bất kỳ thủ thuật không chuẩn nào.

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

tất cả những gì bạn phải làm ở đây để có thể sử dụng instanceof là ném fixError mới thay vì chỉ sửaError
BT

@BT: Không phải với fixErrorchức năng trên. Thêm một newkhi gọi nó sẽ chỉ tạo ra một đối tượng bị ném đi.
TJ Crowder

Ồ tôi đoán tôi có nghĩa là sử dụng "instanceof fixError" - tất nhiên sau đó "Lỗi của instanceof" sẽ không hoạt động .. tôi đoán điều đó tệ hơn ..
BT

0

Một cách khác, có thể không hoạt động trong tất cả các môi trường. Được đảm bảo rằng nó hoạt động trong nodejs 0.8 Cách tiếp cận này sử dụng một cách không chuẩn để sửa đổi prop proto nội bộ

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

0

Nếu bạn đang sử dụng Node / Chrome. Đoạn mã sau sẽ giúp bạn mở rộng đáp ứng các yêu cầu sau.

  • err instanceof Error
  • err instanceof CustomErrorType
  • console.log () trả về [CustomErrorType]khi được tạo bằng một thông báo
  • console.log () trả về [CustomErrorType: message]khi được tạo mà không có thông báo
  • throw / stack cung cấp thông tin tại điểm lỗi được tạo.
  • Hoạt động tối ưu trong Node.JS và Chrome.
  • Sẽ vượt qua kiểm tra cá thể trong Chrome, Safari, Firefox và IE 8+, nhưng sẽ không có ngăn xếp hợp lệ bên ngoài Chrome / Safari. Tôi ổn với điều đó vì tôi có thể gỡ lỗi trong chrome, nhưng mã yêu cầu các loại lỗi cụ thể sẽ vẫn hoạt động trên trình duyệt chéo. Nếu bạn chỉ cần Node, bạn có thể dễ dàng loại bỏ các ifcâu lệnh và bạn vẫn ổn .

Đoạn trích

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

Sử dụng

var err = new CustomErrorType("foo");

Đầu ra

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

Phần sau đây được lấy từ Lỗi tài liệu chính thức của 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
    }
});

-1

Hãy thử một đối tượng nguyên mẫu mới cho từng phiên bản của loại lỗi do người dùng xác định. Nó cho phép instanceofkiểm tra hoạt động như loại cộng và thông báo thông thường được báo cáo chính xác trong Firefox và 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;
}

Lưu ý rằng một mục bổ sung sẽ đi trước ngăn xếp chính xác.


Không hoạt động. Hãy thử : var a = new NotImplementedError('a'), b = new NotImplementedError('b');. Bây giờ a instanceof NotImplementedError == falseb instanceof NotImplementedError == true
jjrv

-1

Đây là cách nhanh nhất để làm điều đó:

    let thisVar = false

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

-3

cách dễ dàng hơn. Bạn có thể làm cho đối tượng của mình kế thừa từ đối tượng Lỗi. Thí dụ:

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

những gì chúng ta đang làm là sử dụng hàm gọi () gọi hàm tạo của lớp Error, về cơ bản giống như việc thực hiện kế thừa lớp trong các ngôn ngữ hướng đối tượng khác.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.