맞춤 예외 유형


224

JavaScript에서 사용자 정의 예외에 대한 사용자 정의 유형을 정의 할 수 있습니까? 그렇다면 어떻게해야합니까?


3
조심하십시오. 10 분 안에 JavaScript에 따르면 상자에 넣지 않은 값을 던지면 스택 추적이 표시되지 않습니다.
야누스 트롤 슨

exceptionsjs.com 은 사용자 정의 예외를 생성하는 기능을 제공하며 ArgumentException 및 NotImplemented를 포함하여 누락 된 예외를 기본적으로 제공합니다.
Steven Wexler 2

답변:


232

에서 WebReference :

throw { 
  name:        "System Error", 
  level:       "Show Stopper", 
  message:     "Error detected. Please contact the system administrator.", 
  htmlMessage: "Error detected. Please contact the <a href=\"mailto:sysadmin@acme-widgets.com\">system administrator</a>.",
  toString:    function(){return this.name + ": " + this.message;} 
}; 

7
@ b.long "자바 스크립트 : 좋은 부분"(위대한 책 IMO)에 있습니다. 이 Google 도서 미리보기에는 다음 섹션이 표시됩니다. books.google.com/books?id=PXa2bby0oQ0C&pg=PA32&lpg=PA32
orip

11
toString 메소드를 추가하면 자바 스크립트 콘솔에 멋지게 표시됩니다. 그렇지 않으면 다음과 같이 표시됩니다. toString과 함께 Uncaught # <Object>는 다음과 같이 표시됩니다. 시스템 관리자에게 문의하십시오.
JDC

11
이렇게하면 오류에서 상속하지 않으면 추적을 스택 할 수 없습니다.
Luke H

이 맞춤 오류로만 작동하도록 catch 블록 내에서 어떻게 필터링 할 수 있습니까?
Overdrivr

@overdrivr something⦄ catch (e) { if (e instanceof TypeError) { … } else { throw e; } }또는 ⦃⦄ 와 같은 것 catch (e) { switch (e.constructor) { case TypeError: …; break; default: throw e; }.
sam boosalis

92

Error에서 프로토 타입으로 상속되는 사용자 정의 예외를 작성해야합니다. 예를 들면 다음과 같습니다.

function InvalidArgumentException(message) {
    this.message = message;
    // Use V8's native method if available, otherwise fallback
    if ("captureStackTrace" in Error)
        Error.captureStackTrace(this, InvalidArgumentException);
    else
        this.stack = (new Error()).stack;
}

InvalidArgumentException.prototype = Object.create(Error.prototype);
InvalidArgumentException.prototype.name = "InvalidArgumentException";
InvalidArgumentException.prototype.constructor = InvalidArgumentException;

이것은 기본적으로 무엇의 단순화 된 버전입니다 disfated 스택 추적은 파이어 폭스와 다른 브라우저에서 작동하는 강화하여 전술 기록했다. 그가 게시 한 것과 동일한 테스트를 충족합니다.

용법:

throw new InvalidArgumentException();
var err = new InvalidArgumentException("Not yet...");

그리고 그것은 예상됩니다 :

err instanceof InvalidArgumentException          // -> true
err instanceof Error                             // -> true
InvalidArgumentException.prototype.isPrototypeOf(err) // -> true
Error.prototype.isPrototypeOf(err)               // -> true
err.constructor.name                             // -> InvalidArgumentException
err.name                                         // -> InvalidArgumentException
err.message                                      // -> Not yet...
err.toString()                                   // -> InvalidArgumentException: Not yet...
err.stack                                        // -> works fine!

80

다음과 같이 자신의 예외와 처리를 구현할 수 있습니다.

// define exceptions "classes" 
function NotNumberException() {}
function NotPositiveNumberException() {}

// try some code
try {
    // some function/code that can throw
    if (isNaN(value))
        throw new NotNumberException();
    else
    if (value < 0)
        throw new NotPositiveNumberException();
}
catch (e) {
    if (e instanceof NotNumberException) {
        alert("not a number");
    }
    else
    if (e instanceof NotPositiveNumberException) {
        alert("not a positive number");
    }
}

모든 브라우저에서 작동하지는 않지만 유형이 지정된 예외를 잡기위한 또 다른 구문이 있습니다 (예 : IE에서는 그렇지 않음).

// define exceptions "classes" 
function NotNumberException() {}
function NotPositiveNumberException() {}

// try some code
try {
    // some function/code that can throw
    if (isNaN(value))
        throw new NotNumberException();
    else
    if (value < 0)
        throw new NotPositiveNumberException();
}
catch (e if e instanceof NotNumberException) {
    alert("not a number");
}
catch (e if e instanceof NotPositiveNumberException) {
    alert("not a positive number");
}

2
MSN 웹 사이트는 조건 캐치에 대한 다음 경고를 전달합니다. 비표준 이 기능은 비표준이며 표준 트랙이 아닙니다. 웹이있는 프로덕션 사이트에서는 사용하지 마십시오. 모든 사용자에게 적용되는 것은 아닙니다. 구현 간에는 큰 비 호환성이있을 수 있으며 향후 동작이 변경 될 수 있습니다.
Lawrence Dol

40

예. 정수, 문자열, 객체 등 원하는 것을 던질 수 있습니다. 객체를 던지려면 다른 상황에서 객체를 만든 것처럼 새 객체를 만든 다음 던지기 만하면됩니다. Mozilla의 Javascript 참조 에는 몇 가지 예가 있습니다.


26
function MyError(message) {
 this.message = message;
}

MyError.prototype = new Error;

이것은 다음과 같은 사용을 허용합니다 ..

try {
  something();
 } catch(e) {
  if(e instanceof MyError)
   doSomethingElse();
  else if(e instanceof Error)
   andNowForSomethingCompletelyDifferent();
}

이 간단한 예제는 Error의 프로토 타입을 상속하지 않더라도 정확히 같은 방식으로 작동하지 않습니까? 이 예제에서 어떤 이점이 있는지 명확하지 않습니다.
EleventyOne

1
아니요, e instanceof Error거짓 일 것입니다.
Morgan ARR Allen

과연. 그러나 e instanceof MyError사실이므로 else if(e instanceof Error)진술은 결코 평가되지 않을 것입니다.
EleventyOne

이것이 바로이 스타일의 try / catch 작동 방식의 예일뿐입니다. else if(e instanceof Error)마지막 캐치 위치는 어디 입니까? 아마도 else내가 포함하지 않은 간단한 것 같습니다. default:switch 문에서 와 비슷 하지만 오류가 있습니다.
Morgan ARR Allen 4

15

한마디로 :

  • 트랜스 파일러없이 ES6 사용하는 경우 :

    class CustomError extends Error { /* ... */}

    현재 모범 사례에 대해서는 ES6 구문으로 Javascript에서 오류 확장을 참조하십시오.

  • Babel 트랜스 파일러를 사용하는 경우 :

옵션 1 : babel-plugin-transform-builtin-extend 사용

옵션 2 : 직접 해보십시오 (동일한 라이브러리에서 영감을 얻음)

    function CustomError(...args) {
      const instance = Reflect.construct(Error, args);
      Reflect.setPrototypeOf(instance, Reflect.getPrototypeOf(this));
      return instance;
    }
    CustomError.prototype = Object.create(Error.prototype, {
      constructor: {
        value: Error,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
    Reflect.setPrototypeOf(CustomError, Error);
  • 순수한 ES5를 사용하는 경우 :

    function CustomError(message, fileName, lineNumber) {
      const instance = new Error(message, fileName, lineNumber);
      Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
      return instance;
    }
    CustomError.prototype = Object.create(Error.prototype, {
      constructor: {
        value: Error,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
    if (Object.setPrototypeOf){
        Object.setPrototypeOf(CustomError, Error);
    } else {
        CustomError.__proto__ = Error;
    }
  • 대안 : Classtrophobic framework 사용

설명:

ES6 및 Babel을 사용하여 Error 클래스를 확장하는 것이 왜 문제입니까?

CustomError 인스턴스는 더 이상 인식되지 않기 때문입니다.

class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false

사실, 바벨의 공식 문서에서, 당신은 어떤 내장 된 자바 스크립트 클래스를 확장 할 수 없습니다 와 같은 Date, Array, DOM또는 Error.

문제는 여기에 설명되어 있습니다.

다른 SO 답변은 어떻습니까?

주어진 모든 답변으로 문제가 instanceof해결되지만 일반적인 오류가 발생하지 않습니다 console.log.

console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error↵    at CustomError (<anonymous>:4:19)↵    at <anonymous>:1:5"}

위에서 언급 한 방법을 사용하는 동안 instanceof문제를 해결할뿐만 아니라 정기적 인 오류를 유지하십시오 console.log.

console.log(new CustomError('test'));
// output:
// Error: test
//     at CustomError (<anonymous>:2:32)
//     at <anonymous>:1:5

11

다음은 native Error동작 과 완전히 동일한 사용자 지정 오류를 만드는 방법 입니다. 이 기술 현재 Chrome 및 node.js에서만 작동합니다 . 또한 그것이 무엇을 이해하지 못한다면 사용하지 않는 것이 좋습니다 .

Error.createCustromConstructor = (function() {

    function define(obj, prop, value) {
        Object.defineProperty(obj, prop, {
            value: value,
            configurable: true,
            enumerable: false,
            writable: true
        });
    }

    return function(name, init, proto) {
        var CustomError;
        proto = proto || {};
        function build(message) {
            var self = this instanceof CustomError
                ? this
                : Object.create(CustomError.prototype);
            Error.apply(self, arguments);
            Error.captureStackTrace(self, CustomError);
            if (message != undefined) {
                define(self, 'message', String(message));
            }
            define(self, 'arguments', undefined);
            define(self, 'type', undefined);
            if (typeof init == 'function') {
                init.apply(self, arguments);
            }
            return self;
        }
        eval('CustomError = function ' + name + '() {' +
            'return build.apply(this, arguments); }');
        CustomError.prototype = Object.create(Error.prototype);
        define(CustomError.prototype, 'constructor', CustomError);
        for (var key in proto) {
            define(CustomError.prototype, key, proto[key]);
        }
        Object.defineProperty(CustomError.prototype, 'name', { value: name });
        return CustomError;
    }

})();

결과적으로 우리는

/**
 * name   The name of the constructor name
 * init   User-defined initialization function
 * proto  It's enumerable members will be added to 
 *        prototype of created constructor
 **/
Error.createCustromConstructor = function(name, init, proto)

그런 다음 다음과 같이 사용할 수 있습니다.

var NotImplementedError = Error.createCustromConstructor('NotImplementedError');

그리고 사용 NotImplementedError하면 마찬가지로 Error:

throw new NotImplementedError();
var err = new NotImplementedError();
var err = NotImplementedError('Not yet...');

그리고 그것은 예상됩니다 :

err instanceof NotImplementedError               // -> true
err instanceof Error                             // -> true
NotImplementedError.prototype.isPrototypeOf(err) // -> true
Error.prototype.isPrototypeOf(err)               // -> true
err.constructor.name                             // -> NotImplementedError
err.name                                         // -> NotImplementedError
err.message                                      // -> Not yet...
err.toString()                                   // -> NotImplementedError: Not yet...
err.stack                                        // -> works fine!

그것은 error.stack절대적으로 올바르게 작동하며 NotImplementedError생성자 호출을 포함하지 않습니다 (v8 덕분 Error.captureStackTrace()).

노트. 못생긴 eval()있습니다. 그것이 사용되는 유일한 이유는 올바른 것 err.constructor.name입니다. 필요하지 않으면 모든 것을 약간 단순화 할 수 있습니다.


2
Error.apply(self, arguments)되는 작업에 지정되지 . 크로스 브라우저와 호환되는 스택 추적을 복사하는 것이 좋습니다 .
Kornel

11

나는 종종 프로토 타입 상속을 가진 접근법을 사용합니다. 재정의 toString()하면 Firebug와 같은 도구 [object Object]가 포착되지 않은 예외에 대해 콘솔 대신 실제 정보를 기록한다는 이점이 있습니다 .

instanceof예외 유형을 결정하는 데 사용 합니다.

main.js

// just an exemplary namespace
var ns = ns || {};

// include JavaScript of the following
// source files here (e.g. by concatenation)

var someId = 42;
throw new ns.DuplicateIdException('Another item with ID ' +
    someId + ' has been created');
// Firebug console:
// uncaught exception: [Duplicate ID] Another item with ID 42 has been created

Exception.js

ns.Exception = function() {
}

/**
 * Form a string of relevant information.
 *
 * When providing this method, tools like Firebug show the returned 
 * string instead of [object Object] for uncaught exceptions.
 *
 * @return {String} information about the exception
 */
ns.Exception.prototype.toString = function() {
    var name = this.name || 'unknown';
    var message = this.message || 'no description';
    return '[' + name + '] ' + message;
};

DuplicateIdException.js

ns.DuplicateIdException = function(message) {
    this.name = 'Duplicate ID';
    this.message = message;
};

ns.DuplicateIdException.prototype = new ns.Exception();

8

ES6

새로운 클래스 및 확장 키워드를 사용하면 훨씬 쉬워졌습니다.

class CustomError extends Error {
  constructor(message) {
    super(message);
    //something
  }
}

7

throw 문을 사용하십시오 .

자바 스크립트는 예외 유형이 무엇인지 상관하지 않습니다 (자바처럼). JavaScript는 단지 예외를 발견하고이를 발견하면 예외가 무엇을 말하는지 "보고"볼 수 있습니다.

다른 예외 유형을 던져야하는 경우 예외의 문자열 / 객체 (예 : 메시지)가 포함 된 변수를 사용하는 것이 좋습니다. 필요한 경우 "throw myException"을 사용하고 catch에서 포착 된 예외를 myException과 비교하십시오.


1

MDN 에서이 예 를 참조하십시오 .

여러 개의 오류를 정의해야하는 경우 ( 여기 에서 코드를 테스트 하십시오 !) :

function createErrorType(name, initFunction) {
    function E(message) {
        this.message = message;
        if (Error.captureStackTrace)
            Error.captureStackTrace(this, this.constructor);
        else
            this.stack = (new Error()).stack;
        initFunction && initFunction.apply(this, arguments);
    }
    E.prototype = Object.create(Error.prototype);
    E.prototype.name = name;
    E.prototype.constructor = E;
    return E;
}
var InvalidStateError = createErrorType(
    'InvalidStateError',
    function (invalidState, acceptedStates) {
        this.message = 'The state ' + invalidState + ' is invalid. Expected ' + acceptedStates + '.';
    });

var error = new InvalidStateError('foo', 'bar or baz');
function assert(condition) { if (!condition) throw new Error(); }
assert(error.message);
assert(error instanceof InvalidStateError);  
assert(error instanceof Error); 
assert(error.name == 'InvalidStateError');
assert(error.stack);
error.message;

코드는 주로 다음에서 복사됩니다. JavaScript에서 오류를 확장하는 좋은 방법은 무엇입니까?


1

ES2015 클래스와 함께 사용하기위한 asselin 의 답변에 대한 대안

class InvalidArgumentException extends Error {
    constructor(message) {
        super();
        Error.captureStackTrace(this, this.constructor);
        this.name = "InvalidArgumentException";
        this.message = message;
    }
}

1
//create error object
var error = new Object();
error.reason="some reason!";

//business function
function exception(){
    try{
        throw error;
    }catch(err){
        err.reason;
    }
}

이제 에러 객체에 이유 또는 원하는 속성을 추가하고 검색합니다. 오류를보다 합리적으로 만듭니다.

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