JavaScript에서 사용자 정의 오류를 작성하는 방법


215

어떤 이유로 든 생성자 위임이 다음 스 니펫에서 작동하지 않는 것처럼 보입니다.

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

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

이것을 실행하면 The message is: ''. 이유 또는 새로운 Error하위 클래스 를 만드는 더 좋은 방법이 있는지에 대한 아이디어가 있습니까? 내가 모르는 apply기본 Error생성자에 ing에 문제가 있습니까?


변경 후 NotImplementedError 어설 션의 nie instance가 작동합니까? 이것이 작동하려면 NotImplementedError.prototype.constructor를 명시 적으로 정의해야한다고 생각했습니다.
jayarjo

다음에는 문제를 설명하는 데 필요하지 않은 모든 관련 코드를 제거하십시오. 또한 wtc는 js.jar입니까? 문제를 재현하는 데 필요한가?
BT

2
10 분이 아닌 10 초 안에 이해할 수 있도록이 질문을 수정했습니다.
BT

오류 유형에서 올바르게 상속되는 상속 / 클래스 라이브러리를 만들었습니다. github.com/fresheneesz/proto
BT

1
몇 가지 최고의 답변에 대한 jsfiddle .
Nate

답변:


194

코드를 업데이트하여 프로토 타입을 Error.prototype에 할당하고 인스턴스 및 어설 션이 작동하도록합니다.

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

그러나 나는 단지 당신 자신의 객체를 던지고 이름 속성을 확인합니다.

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

주석을 기준으로 편집

의견을보고 Nicholas Zakas가 기사 에서 Error.prototype하는 new Error()것처럼 프로토 타입을 할당하는 이유를 기억하려고 시도한 후 아래 코드 로 jsFiddle 을 만들었습니다 .

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

콘솔 출력은 이것입니다.

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

이것은 내가 겪었던 "문제"가 오류의 스택 속성이 발생한 위치 new Error()가 아니라 생성 된 행 번호임을 확인합니다 throw e. 그러나 NotImplementedError.prototype.name = "NotImplementedError"선의 부작용 이 오류 개체에 영향을 미치는 것보다 낫습니다 .

또한 명시 적으로 NotImplementedError2설정하지 않으면 .name"Error"와 같습니다. 그러나 주석에서 언급했듯이 해당 버전은 프로토 타입을로 설정하기 때문에 new Error()설정 NotImplementedError2.prototype.name = "NotImplementedError2"하고 괜찮을 수 있습니다.


45
가장 좋은 대답이지만 Error.prototype직접 찍는 것은 나쁜 형태 일 것입니다. 나중에 NotImplementedError.prototype.toString객체 를 추가 하려면 이제 별칭을 지정하는 Error.prototype.toString것이 좋습니다 NotImplementedError.prototype = new Error().
cdleary

4
나는 여전히 그 모든 프로토 타입에서 조금 길을 잃었습니다. 예제에서 NotImplementedError.prototype.name이 아닌 this.name에 이름을 지정하는 이유는 무엇입니까? 당신이 제발 대답 할 수 있습니까, 그것은 나의 이해에 중요합니다 :)
jayarjo

27
code.google.com/p/chromium/issues/detail?id=228909 에 따르면 subclass.prototype = new Error()잘못된 형식입니다. subclass.prototype = Object.create(superclass.prototype)대신 사용해야 합니다. 스택 추적 문제도 해결할 수 있기를 바랍니다.
Gili

8
의미있는 스택 추적을 얻는 간단한 트릭은 생성자에서 오류를 생성하고 스택을 저장하는 것입니다. 생성자에 대해 적절한 호출 스택 + 1 줄을 제공합니다 (적절한 지불 방식) :this.stack = new Error().stack;
Meredian

6
-1; 이것은 잘못이다. 이렇게 NotImplementedError.prototype = Error.prototype;하지 않습니다 instanceof치료를 NotImplementedErrorA와 서브 클래스Error, 그것을 만드는 instanceof동일한 클래스로 대접을. 위의 코드를 콘솔에 붙여 넣고 시도 new Error() instanceof NotImplementedError하면 true분명히 잘못됩니다.
Mark Amery

87

위의 모든 답변은 정말 끔찍합니다. 107 개의 업을 가진 사람이라도! 진정한 대답은 여기 있습니다.

Error 객체에서 상속-메시지 속성은 어디에 있습니까?

TL; DR :

A. message설정되지 않은 이유 는 Error새로운 Error 객체를 반환하고 어떤 식 으로든 조작 하지 않는 함수 이기 때문 입니다 this.

B.이 권리를 얻는 방법은 생성자의 적용 결과를 반환하고 일반적인 복잡한 자바 스크립트 방식으로 프로토 타입을 설정하는 것입니다.

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

당신은 아마 모든 비 열거 속성을 통해 열거 할 몇 가지 속임수를 할 수 tmp만 명시 적으로 설정하기보다는 그들을 설정 오류 stackmessage<9하지만 속임수는 IE에서 지원되지 않습니다


2
이 솔루션은 기존 오류로 사용자 지정 오류를 인스턴스화하는 데에도 사용됩니다. 타사 라이브러리를 사용하고 있고 기존 오류를 사용자 정의 유형으로 래핑하려는 경우 다른 방법이 제대로 작동하지 않습니다. 참고로, 기존 오류를 전달하여 바닐라 오류를 인스턴스화 할 수 있습니다.
Kyle Mueller

1
return this생성자 안에 있으면 안됩니다 .
Onur Yıldırım

13
나는 간소화 및이 방법을 조금 개선 : jsbin.com/rolojuhuya/1/edit?js,console
매트 캔터에게

3
@ MatKantor는 아마도 그 대답을할까요? 나는 당신을 가장 좋아한다고 생각합니다.
mpoisot

2
대신 temp.name = this.name = 'MyError'할 수 있습니다 temp.name = this.name = this.constructor.name. 그렇게하면 하위 클래스 MyError에서도 작동 합니다.
Jo Liss

45

ES2015에서는 class이를 깨끗하게 수행 하는 데 사용할 수 있습니다 .

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

이 글로벌 수정하지 않습니다 Error프로토 타입을, 당신은 사용자 정의 할 수 있습니다 message, name및 기타 속성, 제대로 스택을 캡처합니다. 또한 꽤 읽을 수 있습니다.

물론 babel코드가 구형 브라우저에서 실행될 경우 와 같은 도구를 사용해야 할 수도 있습니다 .


23

사람이 사용자 지정 오류를 만드는 방법에 대한 호기심 경우 스택 추적을 얻을 :

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

이 표준 섹션에서는 Error.apply호출이 객체를 초기화하지 않는 이유를 설명 할 수 있습니다 .

15.11.1 함수로 호출 된 오류 생성자

Error가 생성자가 아닌 함수로 호출되면 새 Error 객체를 만들고 초기화합니다. 따라서 함수 호출 Error (...)는 동일한 인수를 가진 객체 작성 표현식 new Error (...)와 같습니다.

이 경우 Error함수는 생성자로 호출되지 않은 것으로 판단되므로 this객체를 초기화하는 대신 새 Error 인스턴스를 반환 합니다.

다음 코드를 사용한 테스트는 실제로 이것이 일어나고 있음을 보여줍니다.

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

이것이 실행될 때 다음 출력이 생성됩니다.

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

사용자 정의 오류 클래스를 사용하여 이것을 어떻게 시뮬레이트 할 수 있습니까? 예를 들어, 내 사용자 정의 오류 클래스를 인스턴스를 생성하는 함수와 생성자로 사용하는 방법은 무엇입니까?
Lea Hayes

아니요, 사실이 아닙니다. 새로운 Error 인스턴스를 반환하면 그의 msg 속성이 작동합니다.
BT

@BT 방법은 새 인스턴스에 MSG 속성에 MSG 속성에 어떤 영향을 미치는가 thisError.apply(this, arguments);? 여기서 Error를 호출하면 새 객체가 생성됩니다. 에 이미 구성된 객체를 초기화하지 않습니다 nie.
Dave

@ BT 나는 내가 말하려고하는 것을 분명히하기 위해 예제 코드를 추가했습니다.
Dave

@Dave 나는 여기서 목적을 오해했을 수도 있지만 NotImplementedError구현에서 returned변수를 반환 해서는 안 됩니까?
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
이것이 가장 좋은 대답입니다. 간결하고이 방법으로 작성된 예외는 모든 상황에서 올바르게 작동합니다. 또한 사소하지 않은 응용 프로그램에서 매우 중요한 스택 추적을 유지합니다. "prototype = new Error ()"만 "prototype = Object.create (Error.prototype)"으로 바꿉니다. Node.js를위한 작은 라이브러리가 있습니다 : npmjs.com/package/node-custom-errors
Lukasz Korzybski

6

나는 이것과 비슷한 문제가 있었다. 내 오류 요구가 될 수 있습니다 instanceof모두 ErrorNotImplemented, 또한 콘솔에서 일관된 역 추적을 생성 할 필요가있다.

내 해결책 :

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로 실행 한 결과 :

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)

오류는 내 기준 중 3 가지를 모두 통과하며 stack속성이 비표준 이지만 대부분의 최신 브라우저에서 지원 되며 내 경우에는 허용됩니다.


5

Joyent 에 따르면 스택 속성 (여기에 주어진 많은 답변에서 볼 수 있음)이 성능에 부정적인 영향을 미치기 때문에 엉망이되어서는 안됩니다. 그들이하는 말은 다음과 같습니다.

스택 : 일반적으로 이것을 망쳐 놓지 마십시오. 보강하지 마십시오. V8은 누군가가 실제로 속성을 읽는 경우에만 계산하여 처리 할 수있는 오류에 대한 성능을 크게 향상시킵니다. 속성을 보강하기 위해 속성을 읽는다면 호출자가 스택을 필요로하지 않더라도 비용을 지불하게됩니다.

나는 원래의 오류 를 줄이려 는 아이디어를 좋아하고 언급 하고 싶다 .

위에서 언급 한 것을 고려하여 사용자 정의 오류를 만드는 방법은 다음과 같습니다.

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

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

내 솔루션을 모듈에 넣었습니다. https://www.npmjs.com/package/rerror


3

나는 다음과 같이하고 싶다 :

  • toString ()이 던지도록 이름을 사용하십시오."{code}: {message}"
  • 스택 트레이스에서 동일하게 나타나도록 동일한 것을 super로 반환하십시오.
  • 코드를 부착 error.code검사가 / 코드를 분석하는 것이 더 나은 코드는 예를 들어 지역화 할 수있는 메시지를 확인하는 것보다 같이
  • error.message대안으로 메시지 첨부error.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

방금 이와 같은 것을 구현해야했고 내 오류 구현에서 스택이 손실되었음을 알았습니다. 내가해야 할 일은 더미 오류를 만들고 그에서 스택을 검색하는 것이 었습니다.

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

이것은 메시지를 설정하지 않습니다
BT

2

생성자 패턴을 사용하여 새 오류 객체를 만들었습니다. 인스턴스 와 같은 프로토 타입 체인을 정의했습니다 Error. MDN 오류 생성자 참조를 참조하십시오.

요지 에서이 스 니펫을 확인할 수 있습니다 .

이행

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

용법

CustomError 생성자는 메시지를 빌드하기 위해 많은 인수를받을 수 있습니다. 예 :

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;

그리고 이것이 커스텀 에러의 모습입니다 :

맞춤형 오류 프로토 타입 체인


다운 투표 한 사람, 당신은 논쟁이 있거나 투표 할 이유가 있습니까? 또는 코드의 의도를 이해하지 못합니다.
jherax

방금이 페이지를 탐색하는 동안 실수로 downvote 버튼을 클릭해야한다는 것을 알았습니다 (휴대 전화에서 탐색하는 것처럼). 나는 내 역사를 탐색하는 동안 오늘만 주목했다. 의도적 인 것은 아니지만 유예 기간이 지났으므로 취소 할 수 없습니다. 유익한 정보를 제공했으며 그럴 가치가 없습니다. 수정하면 다운 보트를 행복하게 취소합니다. 미안합니다.
jschr

1

생성자는 팩토리 메소드와 같아야하고 원하는 것을 리턴합니다. 추가 메소드 / 속성이 필요한 경우이를 리턴하기 전에 오브젝트에 추가 할 수 있습니다.

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

x = new NotImplementedError();

왜 당신이 이것을 해야하는지 모르겠습니다. 왜 사용하지 new Error...않습니까? 사용자 정의 예외는 실제로 JavaScript (또는 형식화되지 않은 언어)를 많이 추가하지 않습니다.


2
단일 catch 블록 만 지정할 수 있으므로 JavaScript에서 Error-type-hierarchy 또는 object-value를 켜야합니다. 귀하의 솔루션에서 (x instanceof NotImplementedError)가 false이므로 제 경우에는 허용되지 않습니다.
cdleary

1

이것은 Cesium DeveloperError에서 훌륭하게 구현됩니다.

간단한 형태로 :

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

// Later on...

throw new NotImplementedError();

스택에 오류 생성자를위한 추가 행이 포함되어 있다는 점을 제외하고는 효과적입니다. 이는 문제가 될 수 있습니다.
SystemParadox

또한 error instanceof Error테스트를 통과하지 못 하므로 도움이 될 수 있습니다.
Lauren

1

이것은 내 구현입니다.

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

사용법 # 1 :

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

사용법 # 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

를 사용할 수 없게하기 위해 instanceof다음은 원래 스택 추적을 유지하고 비표준 트릭을 사용하지 않습니다.

// 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를 사용하기 위해 여기서해야 할 일은 단지 fixError 대신에 새로운 fixError를 던지는 것입니다
BT

@BT : fixError위 기능이 아닙니다 . new호출 할 때를 추가 하면 버려진 객체가 생성됩니다.
TJ Crowder

오 나는 "fixError instanceof를"을 사용하여 의미 추측 -하지 작업 .. 난 그게 더 나쁜 것 같아요 것 "오류 instanceof를"물론 다음의 ..
BT

0

또 다른 대안은 모든 환경에서 작동하지 않을 수 있습니다. 가장 작은 방법은 nodejs 0.8에서 작동한다는 것입니다.

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

0

노드 / 크롬을 사용중인 경우 다음 스 니펫은 다음 요구 사항을 충족하는 확장 프로그램을 제공합니다.

  • err instanceof Error
  • err instanceof CustomErrorType
  • [CustomErrorType]메시지와 함께 생성되면 console.log ()가 반환
  • [CustomErrorType: message]메시지없이 만들면 console.log ()가 반환
  • throw / stack은 오류가 생성 된 시점의 정보를 제공합니다.
  • Node.JS 및 Chrome에서 최적으로 작동합니다.
  • Chrome, Safari, Firefox 및 IE 8 이상에서는 instanceof 검사를 통과하지만 Chrome / Safari 외부에 유효한 스택은 없습니다. 크롬으로 디버깅 할 수 있기 때문에 괜찮습니다. 그러나 특정 오류 유형이 필요한 코드는 여전히 크로스 브라우저에서 작동합니다. Node 만 필요한 경우 if명령문을 쉽게 제거 할 수 있으며 계속 진행할 수 있습니다.

단편

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

용법

var err = new CustomErrorType("foo");

산출

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

다음은 공식 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

사용자 정의 오류 유형의 각 인스턴스에 대해 새로운 프로토 타입 객체를 사용해보십시오. 그것은 수 instanceof검사가 제대로 파이어 폭스와 V8 (쵸메, 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;
}

추가 항목이 그렇지 않으면 올바른 스택보다 우선합니다.


작동하지 않습니다. 시도하십시오 : var a = new NotImplementedError('a'), b = new NotImplementedError('b');. 이제 a instanceof NotImplementedError == falseb instanceof NotImplementedError == true
jjrv

-1

가장 빠른 방법입니다.

    let thisVar = false

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

-3

더 쉬운 방법. 객체를 Error 객체에서 상속 할 수 있습니다. 예:

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

우리가하고있는 일은 Error 클래스의 생성자를 호출하는 call () 함수를 사용하는 것이므로 기본적으로 다른 객체 지향 언어로 클래스 상속을 구현하는 것과 동일합니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.