JavaScript에서 사용자 정의 예외에 대한 사용자 정의 유형을 정의 할 수 있습니까? 그렇다면 어떻게해야합니까?
JavaScript에서 사용자 정의 예외에 대한 사용자 정의 유형을 정의 할 수 있습니까? 그렇다면 어떻게해야합니까?
답변:
에서 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;}
};
catch (e) { if (e instanceof TypeError) { … } else { throw e; } }
또는 ⦃⦄ 와 같은 것 catch (e) { switch (e.constructor) { case TypeError: …; break; default: throw e; }
.
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!
다음과 같이 자신의 예외와 처리를 구현할 수 있습니다.
// 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");
}
예. 정수, 문자열, 객체 등 원하는 것을 던질 수 있습니다. 객체를 던지려면 다른 상황에서 객체를 만든 것처럼 새 객체를 만든 다음 던지기 만하면됩니다. Mozilla의 Javascript 참조 에는 몇 가지 예가 있습니다.
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();
}
e instanceof Error
거짓 일 것입니다.
e instanceof MyError
사실이므로 else if(e instanceof Error)
진술은 결코 평가되지 않을 것입니다.
else if(e instanceof Error)
마지막 캐치 위치는 어디 입니까? 아마도 else
내가 포함하지 않은 간단한 것 같습니다. default:
switch 문에서 와 비슷 하지만 오류가 있습니다.
한마디로 :
트랜스 파일러없이 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
다음은 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
입니다. 필요하지 않으면 모든 것을 약간 단순화 할 수 있습니다.
나는 종종 프로토 타입 상속을 가진 접근법을 사용합니다. 재정의 toString()
하면 Firebug와 같은 도구 [object Object]
가 포착되지 않은 예외에 대해 콘솔 대신 실제 정보를 기록한다는 이점이 있습니다 .
instanceof
예외 유형을 결정하는 데 사용 합니다.
// 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
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;
};
ns.DuplicateIdException = function(message) {
this.name = 'Duplicate ID';
this.message = message;
};
ns.DuplicateIdException.prototype = new ns.Exception();
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에서 오류를 확장하는 좋은 방법은 무엇입니까?
//create error object
var error = new Object();
error.reason="some reason!";
//business function
function exception(){
try{
throw error;
}catch(err){
err.reason;
}
}
이제 에러 객체에 이유 또는 원하는 속성을 추가하고 검색합니다. 오류를보다 합리적으로 만듭니다.