답변:
Error 필드에있는 유일한 표준 필드는 message
속성입니다. ( MDN 또는 EcmaScript 언어 사양, 섹션 15.11 참조) 기타 모든 것은 플랫폼에 따라 다릅니다.
대부분의 사람들의 환경을 설정 stack
, 속성을하지만 fileName
하고lineNumber
상속에 사용되는 거의 쓸모가 없습니다.
따라서 최소한의 접근 방식은 다음과 같습니다.
function MyError(message) {
this.name = 'MyError';
this.message = message;
this.stack = (new Error()).stack;
}
MyError.prototype = new Error; // <-- remove this if you do not
// want MyError to be instanceof Error
스택을 스니핑하고, 원치 않는 요소를 시프트 해제하고, fileName 및 lineNumber와 같은 정보를 추출 할 수 있지만, 현재 실행중인 플랫폼 JavaScript에 대한 정보가 필요합니다. 대부분의 경우는 불필요하며 실제로 원한다면 사후에 할 수 있습니다.
사파리 는 주목할만한 예외입니다. stack
속성 은 없지만 던져지는 객체 의 throw
키워드 세트 sourceURL
와 line
속성이 있습니다. 그것들은 정확하다고 보장됩니다.
내가 사용한 테스트 사례는 다음에서 찾을 수 있습니다. JavaScript 자체 제작 오류 객체 비교 .
function MyError(message) { this.message = message; this.stack = Error().stack; } MyError.prototype = Object.create(Error.prototype); MyError.prototype.name = "MyError";
MyError.prototype.constructor = MyError
입니다.
this
합니까?
ES6에서 :
class MyError extends Error {
constructor(message) {
super(message);
this.name = 'MyError';
}
}
var supportsClasses = false; try {eval('class X{}'); supportsClasses = true;} catch (e) {}
this.name = this.constructor.name;
대신 사용하십시오.
한마디로 :
트랜스 파일러없이 ES6 을 사용하는 경우 :
class CustomError extends Error { /* ... */}
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) {
var 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
class CustomError extends Error { /* ... */}
공급 업체별 인수 ( lineNumber
, 등)를 올바르게 처리하지 않습니다 . 'ES6 구문을 사용하는 Javascript의 확장 오류'는 Babel에 따라 다르며 ES5 솔루션이 사용 const
하며 사용자 지정 인수를 처리하지 않습니다.
console.log(new CustomError('test') instanceof CustomError);// false
글을 쓰는 시점 에는 문제가 있었지만 현재 해결되었다는 점에 주목할 가치가 있습니다. 실제로 답변에 연결된 문제 가 해결되었으며 여기 에서 REPL에 코드를 붙여넣고 올바른 프로토 타입 체인으로 인스턴스화하기 위해 코드 가 올바르게 변환되는 방법을 확인하여 올바른 동작을 테스트 할 수 있습니다 .
편집 : 의견을 읽으십시오. 이것은 V8 (Chrome / Node.JS)에서만 잘 작동합니다. 내 의도는 모든 브라우저에서 작동하는 브라우저 간 솔루션을 제공하고 지원이있는 곳에서 스택 추적을 제공하는 것이 었습니다.
편집 : 더 많은 편집을 할 수 있도록이 커뮤니티 위키를 만들었습니다.
V8 용 솔루션 (Chrome / Node.JS)은 Firefox에서 작동하며 IE에서 대부분 올바르게 작동하도록 수정할 수 있습니다. (포스트 끝 참조)
function UserError(message) {
this.constructor.prototype.__proto__ = Error.prototype // Make this an instanceof Error.
Error.call(this) // Does not seem necessary. Perhaps remove this line?
Error.captureStackTrace(this, this.constructor) // Creates the this.stack getter
this.name = this.constructor.name; // Used to cause messages like "UserError: message" instead of the default "Error: message"
this.message = message; // Used to set the message
}
짧은 버전 :
function UserError(message) {
this.constructor.prototype.__proto__ = Error.prototype
Error.captureStackTrace(this, this.constructor)
this.name = this.constructor.name
this.message = message
}
나는 계속 this.constructor.prototype.__proto__ = Error.prototype
함께 모든 코드를 유지하기 위해 함수 내에서. 그러나 당신은 또한 대체 할 수있는 this.constructor
과 UserError
그는 한 번만 호출되는 있도록 함수 외부에 코드를 이동할 수 있습니다.
해당 경로로 이동 하면 처음 던지기 전에 해당 회선에 전화해야합니다UserError
.
순서에 관계없이 함수가 먼저 작성되므로주의해야 할 점은 함수에 적용되지 않습니다. 따라서 문제없이 파일 끝으로 함수를 이동할 수 있습니다.
브라우저 호환성
Firefox 및 Chrome (및 Node.JS)에서 작동하며 모든 약속을 채 웁니다.
다음에서 Internet Explorer가 실패합니다
오류는 err.stack
"내 잘못이 아니다"로 시작할 필요가 없습니다 .
Error.captureStackTrace(this, this.constructor)
존재하지 않으므로 다른 것을해야합니다.
if(Error.captureStackTrace) // AKA if not IE
Error.captureStackTrace(this, this.constructor)
toString
서브 클래 싱 할 때 존재하지 않습니다 Error
. 따라서 추가해야합니다.
else
this.toString = function () { return this.name + ': ' + this.message }
IE는 고려하지 않을 것이다 UserError
을 할 instanceof Error
당신은 당신이 전에 약간의 시간 다음 실행하지 않으면throw UserError
UserError.prototype = Error.prototype
Error.call(this)
실제로 수정하지 않고 오류를 반환 하기 때문에 아무것도하지 않습니다 this
.
UserError.prototype = Error.prototype
오해의 소지가 있습니다. 이것은 상속을하지 않습니다. 이것은 그것들 을 같은 클래스로 만듭니다.
Object.setPrototypeOf(this.constructor.prototype, Error.prototype)
선호하는 것으로 생각 this.constructor.prototype.__proto__ = Error.prototype
합니다.
모든 다른 유형의 오류에 대한 상용구 를 피하기 위해 일부 솔루션의 지혜를 createErrorType
함수 로 결합했습니다 .
function createErrorType(name, init) {
function E(message) {
if (!Error.captureStackTrace)
this.stack = (new Error()).stack;
else
Error.captureStackTrace(this, this.constructor);
this.message = message;
init && init.apply(this, arguments);
}
E.prototype = new Error();
E.prototype.name = name;
E.prototype.constructor = E;
return E;
}
그런 다음 다음과 같이 새 오류 유형을 쉽게 정의 할 수 있습니다 .
var NameError = createErrorType('NameError', function (name, invalidChar) {
this.message = 'The name ' + name + ' may not contain ' + invalidChar;
});
var UnboundError = createErrorType('UnboundError', function (variableName) {
this.message = 'Variable ' + variableName + ' is not bound';
});
this.name = name;
있습니까?
name
프로토 타입에 이미 설정되어 있으므로 더 이상 필요하지 않습니다. 나는 그것을 제거했다. 감사!
에서 2018 , 나는 이것이 가장 좋은 방법이라고 생각; IE9 + 및 최신 브라우저를 지원합니다.
업데이트 : 다른 구현에 대한 비교는 이 테스트 및 저장소 를 참조하십시오 .
function CustomError(message) {
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: 'CustomError'
});
Object.defineProperty(this, 'message', {
enumerable: false,
writable: true,
value: message
});
if (Error.hasOwnProperty('captureStackTrace')) { // V8
Error.captureStackTrace(this, CustomError);
} else {
Object.defineProperty(this, 'stack', {
enumerable: false,
writable: false,
value: (new Error(message)).stack
});
}
}
if (typeof Object.setPrototypeOf === 'function') {
Object.setPrototypeOf(CustomError.prototype, Error.prototype);
} else {
CustomError.prototype = Object.create(Error.prototype, {
constructor: { value: CustomError }
});
}
또한 다른 답변에 널리 사용되는 __proto__
속성은 더 이상 사용되지 않습니다 .
setPrototypeOf()
있습니까? 적어도 MDN에 따르면 .prototype
생성자 에서 속성을 설정하여 동일한 작업을 수행 할 수있는 경우 (사용 else
하지 않는 탐색 블록 에서 수행하는 것처럼) 동일한 작업을 수행 할 수 있다면 일반적으로 사용 하지 않는 것이 setPrototypeOf
좋습니다.
setPrototypeOf
. 그러나 OP가 요구하는대로 여전히 필요한 경우 기본 제공 방법을 사용해야합니다. MDN에서 알 수 있듯이 이것은 객체의 프로토 타입을 설정하는 올바른 방법으로 간주됩니다. 다시 말해 MDN은 프로토 타입을 변경하지 않고 (성능 및 최적화에 영향을 미치기 때문에)을 사용해야한다고 말합니다 setPrototypeOf
.
CustomError.prototype = Object.create(Error.prototype)
) 에서 간단하게 라인을 사용할 수 있습니다 . 또한의 Object.setPrototypeOf(CustomError, Error.prototype)
새 인스턴스에 대한 프로토 타입을 지정하지 않고 생성자 자체의 프로토 타입을 설정합니다 CustomError
. 어쨌든, 2016 년에는 실제로 오류를 확장하는 더 좋은 방법이 있다고 생각하지만 여전히 Babel과 함께 사용하는 방법을 알아 내고 있습니다 : github.com/loganfsmyth/babel-plugin-transform-builtin-extend/…
CustomError.prototype = Object.create(Error.prototype)
프로토 타입도 바꾸고 있습니다. ES5에는 내장 확장 / 상속 로직이 없으므로 변경해야합니다. 나는 당신이 언급 한 babel 플러그인이 비슷한 일을한다고 확신합니다.
Object.setPrototypeOf
사용이 의미가없는 이유를 설명하는 요점을 만들었습니다 . 아마도 당신은 글을 쓰는 것을 의미 했을 것입니다-약간 더 의미가 있습니다 (단순히 설정하는 것보다 이점을 제공하지는 않지만 ). Object.setPrototypeOf(CustomError.prototype, Error.prototype)
CustomError.prototype
완벽을 기하기 위해-이전의 답변 중 어느 것도이 방법을 언급하지 않았기 때문에-Node.js로 작업하고 브라우저 호환성에 신경 쓸 필요가 없다면 내장 된 기능으로 원하는 효과를 얻는 것이 매우 쉽습니다. inherits
의 util
모듈 ( 공식 문서 여기 ).
예를 들어, 오류 코드를 첫 번째 인수로 사용하고 오류 메시지를 두 번째 인수로 사용하는 사용자 정의 오류 클래스를 작성한다고 가정하십시오.
custom-error.js 파일 :
'use strict';
var util = require('util');
function CustomError(code, message) {
Error.captureStackTrace(this, CustomError);
this.name = CustomError.name;
this.code = code;
this.message = message;
}
util.inherits(CustomError, Error);
module.exports = CustomError;
이제 당신은 인스턴스화하고 전달 / 던질 수 있습니다 CustomError
:
var CustomError = require('./path/to/custom-error');
// pass as the first argument to your callback
callback(new CustomError(404, 'Not found!'));
// or, if you are working with try/catch, throw it
throw new CustomError(500, 'Server Error!');
이 스 니펫을 사용하면 스택 추적에 올바른 파일 이름과 행이 있으며 오류 인스턴스의 이름이 올바른 것입니다!
이는 대상 객체에 속성 captureStackTrace
을 생성하는 메소드 사용 stack
(이 경우 CustomError
인스턴스화 됨) 으로 인해 발생합니다 . 작동 방식에 대한 자세한 내용은 여기 에서 설명서를 확인 하십시오 .
this.message = this.message;
이것이 잘못되었거나 JS에 대해 모르는 미친 것들이 있습니까?
Crescent Fresh의 답변은 투표율이 높습니다. 그의 경고는 유효하지 않지만 그가 다루지 않은 다른 제한이 있습니다.
첫째, 초승달의 "주의 사항"단락의 추론은 의미가 없습니다. 이 설명은 여러 개의 catch 문과 비교하여 "if if (Error instance of MyError) else ..."코딩이 다소 부담 스럽거나 장황하다는 것을 의미합니다. 단일 catch 블록에있는 여러 개의 instanceof 문은 여러 catch 문과 마찬가지로 간결합니다. 트릭없이 깨끗하고 간결한 코드입니다. 이것은 Java의 훌륭한 던지기 가능한 하위 유형별 오류 처리를 에뮬레이트하는 좋은 방법입니다.
WRT는 "서브 클래스의 메시지 특성이 설정되지 않은 것으로 나타납니다."는 올바르게 구성된 오류 서브 클래스를 사용하는 경우에는 해당되지 않습니다. 자신 만의 ErrorX Error 서브 클래스를 만들려면 "var MyError ="로 시작하는 코드 블록을 복사하여 "MyError"라는 단어를 "ErrorX"로 변경하십시오. 서브 클래스에 사용자 정의 메소드를 추가하려면 샘플 텍스트를 따르십시오.
JavaScript 오류 서브 클래 싱의 실질적이고 중요한 제한은 FireFox와 같이 스택 추적 및 인스턴스 위치를 추적하고보고하는 JavaScript 구현 또는 디버거의 경우 자체 오류 서브 클래스 구현의 위치가 인스턴스화 지점으로 기록된다는 것입니다 직접 오류를 사용한 경우 "new Error (...)"를 실행 한 위치가됩니다. IE 사용자는 아마 눈치 채지 못했지만 FF의 Fire Bug 사용자는 이러한 오류와 함께보고 된 쓸모없는 파일 이름 및 줄 번호 값을 보게되며 실제 인스턴스화 위치를 찾으려면 스택 추적을 요소 # 1로 드릴 다운해야합니다.
Crescent Fresh's
삭제 된 혼란스러운 것입니다 !
이 솔루션은 어떻습니까?
다음을 사용하여 사용자 정의 오류를 발생시키는 대신 :
throw new MyError("Oops!");
Error 객체 (데코레이터와 같은 종류)를 래핑합니다.
throw new MyError(Error("Oops!"));
스택, fileName lineNumber 등과 같은 모든 속성이 올바른지 확인합니다.
그런 다음 속성을 복사하거나 속성을 정의하기 만하면됩니다. 다음은 게터 (IE9)를 사용하는 예입니다.
function MyError(wrapped)
{
this.wrapped = wrapped;
this.wrapped.name = 'MyError';
}
function wrap(attr)
{
Object.defineProperty(MyError.prototype, attr, {
get: function()
{
return this.wrapped[attr];
}
});
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
wrap('name');
wrap('message');
wrap('stack');
wrap('fileName');
wrap('lineNumber');
wrap('columnNumber');
MyError.prototype.toString = function()
{
return this.wrapped.toString();
};
new MyErr (arg1, arg2, new Error())
그리고 MyErr 생성자에서 우리 Object.assign
는 마지막 arg의 속성을 할당하는데 사용 합니다this
일부 사람들이 말했듯이 ES6에서는 상당히 쉽습니다.
class CustomError extends Error { }
그래서 내 앱 (Angular, Typescript)에서 시도했지만 작동하지 않았습니다. 얼마 후 Typescript에서 문제가 발생한다는 것을 알았습니다.
https://github.com/Microsoft/TypeScript/issues/13965를 참조 하십시오.
그렇게하면 매우 혼란 스럽습니다.
class CustomError extends Error {}
try {
throw new CustomError()
} catch(e) {
if (e instanceof CustomError) {
console.log('Custom error');
} else {
console.log('Basic error');
}
}
노드 또는 브라우저에 직접 표시됩니다. Custom error
Typescript 놀이터의 프로젝트에서 Typescript로 실행하십시오 Basic error
.
해결책은 다음을 수행하는 것입니다.
class CustomError extends Error {
// we have to do the following because of: https://github.com/Microsoft/TypeScript/issues/13965
// otherwise we cannot use instanceof later to catch a given type
public __proto__: Error;
constructor(message?: string) {
const trueProto = new.target.prototype;
super(message);
this.__proto__ = trueProto;
}
}
내 솔루션은 제공된 다른 답변보다 간단하며 단점이 없습니다.
특정 프로토 타입 지식이 없어도 Error 프로토 타입 체인과 Error의 모든 속성을 보존합니다. Chrome, Firefox, Node 및 IE11에서 테스트되었습니다.
유일한 제한은 호출 스택 맨 위에있는 추가 항목입니다. 그러나 그것은 쉽게 무시됩니다.
다음은 두 가지 맞춤 매개 변수가 포함 된 예입니다.
function CustomError(message, param1, param2) {
var err = new Error(message);
Object.setPrototypeOf(err, CustomError.prototype);
err.param1 = param1;
err.param2 = param2;
return err;
}
CustomError.prototype = Object.create(
Error.prototype,
{name: {value: 'CustomError', enumerable: false}}
);
사용법 예 :
try {
throw new CustomError('Something Unexpected Happened!', 1234, 'neat');
} catch (ex) {
console.log(ex.name); //CustomError
console.log(ex.message); //Something Unexpected Happened!
console.log(ex.param1); //1234
console.log(ex.param2); //neat
console.log(ex.stack); //stacktrace
console.log(ex instanceof Error); //true
console.log(ex instanceof CustomError); //true
}
setPrototypeOf의 폴리 파일이 필요한 환경의 경우 :
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
};
throw CustomError('err')
대신 다음을 실행해야합니다.throw new CustomError('err')
위의 예에서 Error.apply
(또한 Error.call
)는 나를 위해 아무것도하지 않습니다 (Firefox 3.6 / Chrome 5). 내가 사용하는 해결 방법은 다음과 같습니다.
function MyError(message, fileName, lineNumber) {
var err = new Error();
if (err.stack) {
// remove one stack level:
if (typeof(Components) != 'undefined') {
// Mozilla:
this.stack = err.stack.substring(err.stack.indexOf('\n')+1);
}
else if (typeof(chrome) != 'undefined' || typeof(process) != 'undefined') {
// Google Chrome/Node.js:
this.stack = err.stack.replace(/\n[^\n]*/,'');
}
else {
this.stack = err.stack;
}
}
this.message = message === undefined ? err.message : message;
this.fileName = fileName === undefined ? err.fileName : fileName;
this.lineNumber = lineNumber === undefined ? err.lineNumber : lineNumber;
}
MyError.prototype = new Error();
MyError.prototype.constructor = MyError;
MyError.prototype.name = 'MyError';
다른 사람들이 말했듯이 Node에서는 간단합니다.
class DumbError extends Error {
constructor(foo = 'bar', ...params) {
super(...params);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DumbError);
}
this.name = 'DumbError';
this.foo = foo;
this.date = new Date();
}
}
try {
let x = 3;
if (x < 10) {
throw new DumbError();
}
} catch (error) {
console.log(error);
}
다른 사람들이 이미 말한 내용에 추가하고 싶습니다.
사용자 정의 오류 클래스가 스택 추적에 올바르게 표시되도록하려면 사용자 정의 오류 클래스의 프로토 타입 이름 속성을 사용자 정의 오류 클래스의 이름 속성으로 설정해야합니다. 이것이 내가 의미하는 바입니다.
CustomError.prototype = Error.prototype;
CustomError.prototype.name = 'CustomError';
전체 예는 다음과 같습니다.
var CustomError = function(message) {
var err = new Error(message);
err.name = 'CustomError';
this.name = err.name;
this.message = err.message;
//check if there is a stack property supported in browser
if (err.stack) {
this.stack = err.stack;
}
//we should define how our toString function works as this will be used internally
//by the browser's stack trace generation function
this.toString = function() {
return this.name + ': ' + this.message;
};
};
CustomError.prototype = new Error();
CustomError.prototype.name = 'CustomError';
모든 것이 말되고 완료되면 새로운 예외를 던지고 다음과 같이 보입니다 (크롬 개발 도구에서 느리게 시도했습니다).
CustomError: Stuff Happened. GASP!
at Error.CustomError (<anonymous>:3:19)
at <anonymous>:2:7
at Object.InjectedScript._evaluateOn (<anonymous>:603:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:562:52)
at Object.InjectedScript.evaluate (<anonymous>:481:21)
내 2 센트 :
a) Error.stack
속성에 액세스하면 (일부 답변에서와 같이) 성능이 저하 될 수 있습니다.
b) 한 줄이기 때문에.
c) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error 의 솔루션이 스택 정보를 보존하지 않는 것 같습니다.
//MyError class constructor
function MyError(msg){
this.__proto__.__proto__ = Error.apply(null, arguments);
};
사용 예
http://jsfiddle.net/luciotato/xXyeB/
this.__proto__.__proto__
입니다 MyError.prototype.__proto__
. 따라서 __proto__
MyError 의 FOR ALL INSTANCES를 새로 생성 된 특정 Error로 설정합니다. MyError 클래스 속성과 메서드를 유지하고 새 Error 속성 (.stack 포함)을 __proto__
체인에 넣습니다 .
유용한 스택 정보가있는 MyError 인스턴스를 두 개 이상 가질 수 없습니다.
무엇을 완전히 이해하지 못하면이 솔루션을 사용하지 마십시오 this.__proto__.__proto__=
.
JavaScript 예외는 서브 클래스하기가 어렵 기 때문에 서브 클래스가 아닙니다. 방금 새 Exception 클래스를 만들고 그 안에 Error를 사용합니다. 콘솔의 사용자 정의 예외처럼 보이도록 Error.name 속성을 변경합니다.
var InvalidInputError = function(message) {
var error = new Error(message);
error.name = 'InvalidInputError';
return error;
};
위의 새로운 예외는 일반 오류처럼 발생할 수 있으며 예를 들어 다음과 같이 작동합니다.
throw new InvalidInputError("Input must be a string");
// Output: Uncaught InvalidInputError: Input must be a string
주의 사항 : 스택 추적은 새 오류가 발생하는 곳과 던지는 곳이 아니라 완벽하지 않습니다. Chrome에서는 콘솔에서 직접 전체 스택 추적을 제공하므로 Chrome에서 큰 문제가 아닙니다. 그러나 Firefox에서는 더 문제가 있습니다.
m = new InvalidInputError(); dontThrowMeYet(m);
m = new ...
then을 자주 사용 Promise.reject(m)
합니다. 꼭 필요한 것은 아니지만 코드를 쉽게 읽을 수 있습니다.
Mohsen의 답변에서 지적했듯이 ES6에서는 클래스를 사용하여 오류를 확장 할 수 있습니다. 훨씬 더 쉽고 동작이 기본 오류와 더 일관성이 있지만 불행히도 ES6 이전 브라우저를 지원 해야하는 경우 브라우저에서이를 사용하는 것은 간단하지 않습니다. 구현 방법에 대한 참고 사항은 아래를 참조하십시오. 그러나 그 동안 다른 답변의 최상의 제안 중 일부를 포함하는 비교적 간단한 접근법을 제안합니다.
function CustomError(message) {
//This is for future compatibility with the ES6 version, which
//would display a similar message if invoked without the
//`new` operator.
if (!(this instanceof CustomError)) {
throw new TypeError("Constructor 'CustomError' cannot be invoked without 'new'");
}
this.message = message;
//Stack trace in V8
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CustomError);
}
else this.stack = (new Error).stack;
}
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.name = 'CustomError';
ES6에서는 다음과 같이 간단합니다.
class CustomError extends Error {}
...을 사용하여 ES6 클래스에 대한 지원을 감지 할 수 try {eval('class X{}')
있지만 이전 브라우저에서로드 한 스크립트에 ES6 버전을 포함하려고하면 구문 오류가 발생합니다. 따라서 모든 브라우저를 지원하는 유일한 방법은 eval()
ES6를 지원하는 브라우저에 대해 별도의 스크립트를 동적으로로드하는 것입니다 (예 : AJAX 또는 ). 더 복잡한 것은eval()
모든 환경 (콘텐츠 보안 정책으로 인해)에서 지원되지 않는데, 이는 프로젝트에서 고려하거나 고려하지 않을 수 있습니다.
지금까지는 위의 첫 번째 접근법이나 단순히 Error
확장하지 않고 직접 하는 것이 비 ES6 브라우저를 지원 해야하는 코드에서 실제로 수행 할 수있는 최선의 방법 인 것 같습니다.
일부 사람들이 고려해야 할 또 다른 접근법이 Object.setPrototypeOf()
있습니다. 사용자 정의 오류 유형의 인스턴스이지만 콘솔의 기본 오류처럼 보이고 동작하는 오류 객체를 만드는 데 사용할 수 있는 곳 을 사용 하는 것입니다 ( Ben의 답변 덕분에) 추천을 위해). https://gist.github.com/mbrowne/fe45db61cea7858d11be933a998926a8에 대한 접근 방식은 다음과 같습니다 . 그러나 언젠가 우리는 ES6 만 사용할 수 있다는 것을 감안할 때 개인적으로 그 접근 방식의 복잡성이 가치가 있는지 확신하지 못합니다.
이를 올바르게 수행하는 방법은 생성자로부터 적용 결과를 반환하고 일반적인 복잡한 자바 스크립트 방식으로 프로토 타입을 설정하는 것입니다.
function MyError() {
var tmp = Error.apply(this, arguments);
tmp.name = this.name = 'MyError'
this.stack = tmp.stack
this.message = tmp.message
return this
}
var IntermediateInheritor = function() {}
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor()
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 ...>
이 시점 에서이 작업을 수행하는 방법에 대한 유일한 문제는 (반복했습니다)
stack
및 message
에 포함되지 않은 속성 MyError
및첫 번째 문제는이 답변의 트릭을 사용하여 열거 할 수없는 모든 오류 속성을 반복하여 해결할 수 있습니다. . 객체의 열거 할 수없는 상속 된 속성 이름을 가져올 수 있습니까? , 그러나 이것은 <9에서 지원되지 않습니다. 두 번째 문제는 스택 추적에서 해당 줄을 찢어 해결할 수는 있지만 안전하게 수행하는 방법을 모르겠습니다 (e.stack.toString () ??의 두 번째 줄을 제거하는 것일 수 있습니다 ??).
스 니펫이 모든 것을 보여줍니다.
function add(x, y) {
if (x && y) {
return x + y;
} else {
/**
*
* the error thrown will be instanceof Error class and InvalidArgsError also
*/
throw new InvalidArgsError();
// throw new Invalid_Args_Error();
}
}
// Declare custom error using using Class
class Invalid_Args_Error extends Error {
constructor() {
super("Invalid arguments");
Error.captureStackTrace(this);
}
}
// Declare custom error using Function
function InvalidArgsError(message) {
this.message = `Invalid arguments`;
Error.captureStackTrace(this);
}
// does the same magic as extends keyword
Object.setPrototypeOf(InvalidArgsError.prototype, Error.prototype);
try{
add(2)
}catch(e){
// true
if(e instanceof Error){
console.log(e)
}
// true
if(e instanceof InvalidArgsError){
console.log(e)
}
}
한 걸음 물러서서 왜 그렇게하고 싶을까? 요점은 다른 오류를 다르게 처리하는 것입니다.
예를 들어, 파이썬에서는 catch 문만 catch로 제한 할 수 MyValidationError
있으며, 자바 스크립트에서 비슷한 작업을 수행하려고 할 수 있습니다.
catch (MyValidationError e) {
....
}
자바 스크립트에서는이 작업을 수행 할 수 없습니다. 캐치 블록은 하나만있을 것입니다. 오류에 if 문을 사용하여 유형을 결정해야합니다.
catch(e) {
if(isMyValidationError(e)) {
...
} else {
// maybe rethrow?
throw e;
}
}
대신 유형, 메시지 및 기타 적합한 속성을 가진 원시 객체를 던질 것이라고 생각합니다.
throw { type: "validation", message: "Invalid timestamp" }
그리고 당신이 오류를 잡을 때 :
catch(e) {
if(e.type === "validation") {
// handle error
}
// re-throw, or whatever else
}
error.stack
, 표준 금형 것 그것으로하지 작업, 등 등이 방법은 오류 인스턴스에 속성을 추가하는 것, 예를 들어, 더 나은을var e = new Error(); e.type = "validation"; ...
이것은 George Bailey의 답변을 기반으로합니다. 하지만 원래 아이디어를 확장하고 단순화합니다. CoffeeScript로 작성되었지만 JavaScript로 쉽게 변환 할 수 있습니다. 아이디어는 그것을 감싸는 데코레이터로 Bailey의 사용자 정의 오류를 확장하여 새로운 사용자 정의 오류를 쉽게 만들 수 있도록하는 것입니다.
참고 : 이것은 V8에서만 작동합니다. Error.captureStackTrace
다른 환경 에서는 지원되지 않습니다 .
데코레이터는 오류 유형의 이름을 사용하여 오류 메시지를 가져오고 오류 이름을 묶는 함수를 반환합니다.
CoreError = (@message) ->
@constructor.prototype.__proto__ = Error.prototype
Error.captureStackTrace @, @constructor
@name = @constructor.name
BaseError = (type) ->
(message) -> new CoreError "#{ type }Error: #{ message }"
이제 새 오류 유형을 만드는 것이 간단합니다.
StorageError = BaseError "Storage"
SignatureError = BaseError "Signature"
재미있게, SignatureError
너무 많은 인수로 호출 된 경우 를 던지는 함수를 정의 할 수 있습니다 .
f = -> throw SignatureError "too many args" if arguments.length
이것은 꽤 잘 테스트되었으며 V8에서 완벽하게 작동하고 트레이스 백, 위치 등을 유지하는 것처럼 보입니다.
참고 : new
사용자 지정 오류를 구성 할 때는 사용 은 선택 사항입니다.
오류에 대한 성능에 신경 쓰지 않으면 이것이 할 수있는 가장 작은 것
Object.setPrototypeOf(MyError.prototype, Error.prototype)
function MyError(message) {
const error = new Error(message)
Object.setPrototypeOf(error, MyError.prototype);
return error
}
새로운 MyError (message)없이 사용할 수 있습니다.
Error 생성자가 생성 된 후 프로토 타입을 변경하면 콜 스택과 메시지를 설정할 필요가 없습니다.
모센는 ES6에서 위의 좋은 답을 가지고 그 세트의 이름,하지만 당신은 타이프 라이터를 사용하거나하는 경우 만약 당신이 미래에있어 생활 곳에 희망이 공공 및 민간 클래스 필드에 대한 제안 3 단계 만들어졌습니다. ECMAScript / JavaScript의 일부로 4 단계에 들어가면 이것이 조금 짧다는 것을 알고 싶을 것입니다. 3 단계는 브라우저가 기능 구현을 시작하는 곳이므로 브라우저에서 지원하는 경우 아래 코드가 작동 할 수 있습니다. (새로운 Edge 브라우저 v81에서 테스트되었으며 제대로 작동하는 것 같습니다). 이 기능은 현재 불안정한 기능이지만주의해서 사용해야하며 불안정한 기능에 대한 브라우저 지원을 항상 확인해야합니다. 이 게시물은 주로 브라우저가이를 지원할 수있는 미래의 거주자를위한 것입니다. 지원 확인을 확인 MDN 및 수 있습니까 사용 . 현재 브라우저 시장에서 66 %의 지원을 받고 있지만 그다지 훌륭하지는 않으므로 지금 사용하고 Babel 과 같은 transpiler 또는 TypeScript와 같은 변환기를 사용하지 않으려면 기다리 십시오 .
class EOFError extends Error {
name="EOFError"
}
throw new EOFError("Oops errored");
던질 때 이름이 기록되지 않는 이름없는 오류와 비교하십시오.
class NamelessEOFError extends Error {}
throw new NamelessEOFError("Oops errored");
this.name = 'MyError'
함수 외부로 이동하여로 변경할 수MyError.prototype.name = 'MyError'
있습니다.