[javascript] JavaScript에서 오류를 확장하는 좋은 방법은 무엇입니까?
내 JS 코드에 몇 가지를 던져보고 오류의 인스턴스가되기를 원하지만 다른 것으로 만들고 싶습니다.
파이썬에서는 일반적으로 Exception을 서브 클래스 화합니다.
JS에서해야 할 일은 무엇입니까?
답변
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 자체 제작 오류 객체 비교 .
답변
ES6에서 :
class MyError extends Error {
constructor(message) {
super(message);
this.name = 'MyError';
}
}
답변
한마디로 :
-
트랜스 파일러없이 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
.
문제는 여기에 설명되어 있습니다.
- 기본 확장으로 HTMLELement, Array 등이 중단됨
- Array, Number, Object, String 또는 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
답변
편집 : 의견을 읽으십시오. 이것은 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
답변
모든 다른 유형의 오류에 대한 상용구 를 피하기 위해 일부 솔루션의 지혜를 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';
});
답변
에서 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__
속성은 더 이상 사용되지 않습니다 .
답변
완벽을 기하기 위해-이전의 답변 중 어느 것도이 방법을 언급하지 않았기 때문에-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
인스턴스화 됨) 으로 인해 발생합니다 . 작동 방식에 대한 자세한 내용은 여기 에서 설명서를 확인 하십시오 .