मैं अपने जेएस कोड में कुछ चीजें फेंकना चाहता हूं और मैं चाहता हूं कि उन्हें इंस्टाफॉरेक्ट एरर किया जाए, लेकिन मैं यह भी चाहता हूं कि वे कुछ और हों।
पायथन में, आम तौर पर, एक अपवाद को उप-वर्ग में बदल देगा।
जेएस में क्या करना उचित है?
मैं अपने जेएस कोड में कुछ चीजें फेंकना चाहता हूं और मैं चाहता हूं कि उन्हें इंस्टाफॉरेक्ट एरर किया जाए, लेकिन मैं यह भी चाहता हूं कि वे कुछ और हों।
पायथन में, आम तौर पर, एक अपवाद को उप-वर्ग में बदल देगा।
जेएस में क्या करना उचित है?
जवाबों:
केवल मानक फ़ील्ड त्रुटि ऑब्जेक्ट के पास message
गुण है। (देखें MDN , या ECMAScript भाषा विशिष्टता, खंड 15.11) बाकी सब कुछ मंच विशिष्ट है।
Mosts वातावरण सेट 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
आप स्टैक को सूँघ सकते हैं, उसमें से अवांछित तत्वों को हटा सकते हैं और फाइलनेम और लाइननंबर जैसी जानकारी निकाल सकते हैं, लेकिन ऐसा करने के लिए प्लेटफॉर्म जावास्क्रिप्ट के बारे में जानकारी की आवश्यकता होती है जो वर्तमान में चल रही है। अधिकांश मामले जो अनावश्यक हैं - और आप इसे पोस्टमार्टम में कर सकते हैं यदि आप वास्तव में चाहते हैं।
सफारी एक उल्लेखनीय अपवाद है। कोई stack
संपत्ति नहीं है, लेकिन throw
कीवर्ड सेट sourceURL
और line
उस ऑब्जेक्ट के गुण हैं जिसे फेंक दिया जा रहा है। उन चीजों को सही होने की गारंटी है।
मेरे द्वारा उपयोग किए गए परीक्षण मामलों को यहां पाया जा सकता है: जावास्क्रिप्ट स्व-निर्मित त्रुटि वस्तु तुलना ।
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 { /* ... */}
यदि आप बैबल ट्रांसपिलर का उपयोग कर रहे हैं :
विकल्प 1: बैबल-प्लगइन-ट्रांसफॉर्मेशन-बिलिन-एक्सटेंशन का उपयोग करें
विकल्प 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 ढांचे का उपयोग करें
स्पष्टीकरण:
ES6 और बैबल का उपयोग करके त्रुटि वर्ग का विस्तार क्यों एक समस्या है?
क्योंकि 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
, इत्यादि) को सही तरीके से नहीं संभालता है , 'ईएस 6 सिंटैक्स के साथ जावास्क्रिप्ट में फैली त्रुटि' बैबल विशिष्ट है, आपका ईएस 5 समाधान उपयोग करता है const
और यह कस्टम तर्कों को संभाल नहीं पाता है।
console.log(new CustomError('test') instanceof CustomError);// false
लेखन के समय यह मुद्दा सही था लेकिन अब इसे सुलझा लिया गया है। वास्तव में उत्तर में जुड़ी समस्या को हल कर दिया गया है और हम यहां सही व्यवहार का परीक्षण कर सकते हैं और आरईपीएल में कोड चिपकाकर और यह देख सकते हैं कि कैसे सही प्रोटोटाइप श्रृंखला के साथ त्वरित करने के लिए इसे सही ढंग से ट्रांसप्लेंड किया जाता है।
संपादित करें: कृपया टिप्पणियों को पढ़ें। यह पता चला है कि यह केवल V8 (Chrome / Node.JS) में अच्छा काम करता है। मेरा इरादा क्रॉस-ब्राउज़र समाधान प्रदान करना था, जो सभी ब्राउज़रों में काम करेगा, और स्टैक ट्रेस प्रदान करेगा जहां समर्थन है।
संपादित करें: मैंने अधिक संपादन के लिए अनुमति देने के लिए यह सामुदायिक विकी बनाया।
V8 (Chrome / Node.JS) के लिए समाधान, फ़ायरफ़ॉक्स में काम करता है, और 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
।
वह कार्य फ़ंक्शन लागू नहीं करता है, क्योंकि फ़ंक्शंस पहले बनाए जाते हैं, चाहे कोई भी ऑर्डर हो। इस प्रकार, आप समस्या के बिना फ़ंक्शन को फ़ाइल के अंत में स्थानांतरित कर सकते हैं।
ब्राउज़र संगतता
फ़ायरफ़ॉक्स और क्रोम (और Node.JS) में काम करता है और सभी वादों को पूरा करता है।
इंटरनेट एक्सप्लोरर निम्नलिखित में विफल रहता है
त्रुटियों के 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 }
आईई पर विचार नहीं करेंगे 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()
? कम से कम एमडीएन के अनुसार, इसका उपयोग करने के लिए आमतौर पर हतोत्साहित किया जाता है यदि आप .prototype
निर्माणकर्ता पर संपत्ति सेट करके उसी चीज को पूरा कर सकते हैं (जैसा else
कि आपके पास ब्लॉक में कर रहे हैं जो आपके पास नहीं है setPrototypeOf
)।
setPrototypeOf
। लेकिन अगर आपको अभी भी इसकी आवश्यकता है (जैसा कि ओपी पूछता है), तो आपको अंतर्निहित कार्यप्रणाली का उपयोग करना चाहिए। जैसा कि एमडीएन इंगित करता है, किसी वस्तु के प्रोटोटाइप को सेट करने का यह उचित तरीका माना जाता है। दूसरे शब्दों में, एमडीएन का कहना है कि प्रोटोटाइप में बदलाव न करें (क्योंकि यह प्रदर्शन और अनुकूलन को प्रभावित करता है) लेकिन अगर आपको उपयोग करना है setPrototypeOf
।
CustomError.prototype = Object.create(Error.prototype)
) में अपनी लाइन का उपयोग कर सकते हैं । इसके अलावा, Object.setPrototypeOf(CustomError, Error.prototype)
नए उदाहरणों के लिए प्रोटोटाइप को निर्दिष्ट करने के बजाय स्वयं निर्माता के प्रोटोटाइप को सेट करना है CustomError
। वैसे भी, 2016 में मुझे लगता है कि वास्तव में त्रुटियों का विस्तार करने का एक बेहतर तरीका है, हालांकि मुझे अभी भी पता चल रहा है कि बैबेल के साथ मिलकर इसका उपयोग कैसे किया जाए: github.com/loganfsmyth/babel-plugin-transform-builtin-extil/…
CustomError.prototype = Object.create(Error.prototype)
प्रोटोटाइप भी बदल रहा है। आपको इसे बदलना होगा क्योंकि ES5 में कोई अंतर्निहित विस्तार / इनहेरिट लॉजिक नहीं है। मुझे यकीन है कि आप जिस बबल प्लग इन का उल्लेख करते हैं वह इसी तरह की चीजें करता है।
Object.setPrototypeOf
इसका उपयोग करने का मतलब यहाँ क्यों नहीं है, कम से कम उस तरीके से नहीं जो आप इसका उपयोग कर रहे हैं: gist.github.com/mbrowne/4af54767dc3d529648f5a8aa11dn34348 । शायद आप लिखने का मतलब है 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;
क्या यह गलत है या अभी भी पागल चीजें हैं जो मुझे जेएस के बारे में नहीं पता हैं?
क्रिसेंट फ्रेश का अत्यधिक मत वाला उत्तर भ्रामक है। यद्यपि उसकी चेतावनियां अमान्य हैं, लेकिन अन्य सीमाएँ हैं जिन्हें वह संबोधित नहीं करता है।
सबसे पहले, क्रिसेंट के "कैविट्स:" पैराग्राफ में तर्क का कोई मतलब नहीं है। व्याख्या का अर्थ है कि कोडिंग "अगर (त्रुटि इंस्ट्रूमेंट मायएयर) का एक गुच्छा ..." किसी तरह से कई कैच स्टेटमेंट्स की तुलना में बोझ या क्रिया है। एक ही कैच ब्लॉक में मल्टीपल इंस्टोफ स्टेटमेंट उतने ही संक्षिप्त होते हैं जितने कि कई कैच स्टेटमेंट- बिना किसी ट्रिक्स के क्लीन एंड कॉन्साइज कोड। यह जावा के महान फेंकने योग्य-उपप्रकार-विशिष्ट त्रुटि हैंडलिंग का अनुकरण करने का एक शानदार तरीका है।
WRT "उपवर्ग की संदेश संपत्ति दिखाई नहीं देती है" सेट हो जाता है, यदि आप ठीक से निर्मित त्रुटिक्लास का उपयोग करते हैं तो यह मामला नहीं है। अपनी खुद की ErrorX Error को उपवर्ग बनाने के लिए, बस "var MyError =" के साथ शुरू होने वाले कोड ब्लॉक को कॉपी करें, एक शब्द "MyError" को "ErrorX" में बदल दें। (यदि आप अपने उपवर्ग में कस्टम तरीके जोड़ना चाहते हैं, तो नमूना पाठ का पालन करें)।
जावास्क्रिप्ट त्रुटि उपवर्ग की वास्तविक और महत्वपूर्ण सीमा यह है कि जावास्क्रिप्ट कार्यान्वयन या डिबगर्स के लिए जो ट्रैक करते हैं और स्टैक ट्रेस और स्थान-तत्काल पर रिपोर्ट करते हैं, जैसे कि फ़ायरफ़ॉक्स, आपकी खुद की त्रुटि उपवर्ग कार्यान्वयन में एक स्थान को तत्काल बिंदु के रूप में दर्ज किया जाएगा। वर्ग, जबकि यदि आपने प्रत्यक्ष त्रुटि का उपयोग किया है, तो यह वह स्थान होगा जहां आपने "नई त्रुटि (...)" चलाया था। IE उपयोगकर्ता शायद कभी नोटिस नहीं करेंगे, लेकिन FF पर फायर बग के उपयोगकर्ता इन त्रुटियों के साथ रिपोर्ट किए गए बेकार फ़ाइल नाम और लाइन नंबर मान देखेंगे, और वास्तविक तात्कालिक स्थान को खोजने के लिए तत्व # 1 को स्टैक ट्रेस पर ड्रिल करना होगा।
Crescent Fresh's
है जिसे हटा दिया गया है!
इस समाधान के बारे में कैसे?
इसके बजाय अपने कस्टम त्रुटि का उपयोग कर फेंक:
throw new MyError("Oops!");
आप त्रुटि ऑब्जेक्ट (एक डेकोरेटर की तरह) को लपेटेंगे:
throw new MyError(Error("Oops!"));
यह सुनिश्चित करता है कि सभी विशेषताएँ सही हैं, जैसे कि स्टैक, फ़ाइलनाम लाइननंबर, वगैरह।
इसके बाद आपको केवल या तो विशेषताओं पर कॉपी करना है, या उनके लिए गेटर्स को परिभाषित करना है। यहाँ गेटर्स (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
अंतिम आर्ग के गुण निर्दिष्ट करने के लिए उपयोग करते हैंthis
जैसा कि कुछ लोगों ने कहा है, यह ES6 के साथ काफी आसान है:
class CustomError extends Error { }
इसलिए मैंने कोशिश की कि मेरे ऐप के भीतर, (कोणीय, टाइपस्क्रिप्ट) और यह सिर्फ काम नहीं करे। कुछ समय बाद मैंने पाया है कि समस्या टाइपस्क्रिप्ट: O से आ रही है
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
अपने प्रोजेक्ट में टाइपस्क्रिप्ट खेल के मैदान पर टाइपस्क्रिप्ट के साथ चलाने की कोशिश करें, यह प्रदर्शित होगा 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;
}
}
मेरा समाधान प्रदान किए गए अन्य उत्तरों की तुलना में अधिक सरल है और इसमें डाउनसाइड नहीं है।
यह त्रुटि प्रोटोटाइप श्रृंखला और त्रुटि के सभी गुणों को उनके विशिष्ट ज्ञान की आवश्यकता के बिना सुरक्षित रखता है। यह क्रोम, फ़ायरफ़ॉक्स, नोड और 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
}
उन वातावरणों के लिए जिन्हें सेट पॉलीपोटाइपऑफ की पॉलीफ़िल की आवश्यकता होती है:
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
};
throw CustomError('err')
इसके बजाय चलना चाहिएthrow new CustomError('err')
उपरोक्त उदाहरण में Error.apply
(भी Error.call
) मेरे लिए कुछ भी नहीं करता है (फ़ायरफ़ॉक्स 3.6 / क्रोम 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';
नोड में अन्य लोगों ने कहा है, यह सरल है:
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';
जब सब कहा और किया जाता है, तो आप अपने नए अपवाद को फेंक देते हैं और यह इस तरह दिखता है (मैंने क्रोम डिवाइसेस में lazily यह कोशिश की):
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 के लिए सभी उदाहरणों। यह MyError वर्ग के गुणों और विधियों को रखता है और __proto__
श्रृंखला में नए त्रुटि गुण (.stack) भी डालता है ।
आपके पास उपयोगी स्टैक जानकारी के साथ MyError के एक से अधिक उदाहरण नहीं हो सकते हैं।
यदि आप पूरी तरह से नहीं समझते हैं कि इस समाधान का उपयोग न करें this.__proto__.__proto__=
।
चूंकि जावास्क्रिप्ट अपवाद उप-वर्ग के लिए कठिन हैं, इसलिए मैं उप-वर्ग नहीं करता। मैं बस एक नया अपवाद वर्ग बनाता हूं और इसके अंदर एक त्रुटि का उपयोग करता हूं। मैं 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 पर यह कोई बड़ी बात नहीं है क्योंकि यह आपको कंसोल में सीधे पूर्ण स्टैक ट्रेस प्रदान करता है। उदाहरण के लिए, यह फ़ायरफ़ॉक्स पर अधिक समस्याग्रस्त है।
m = new InvalidInputError(); dontThrowMeYet(m);
m = new ...
तो Promise.reject(m)
। यह कोई आवश्यकता नहीं है, लेकिन कोड को पढ़ना आसान है।
जैसा कि मोहसिन के जवाब में बताया गया है, ईएस 6 में कक्षाओं का उपयोग करके त्रुटियों का विस्तार करना संभव है। यह बहुत आसान है और उनका व्यवहार मूल त्रुटियों के साथ अधिक सुसंगत है ... लेकिन दुर्भाग्यवश ब्राउज़र में इस का उपयोग करना आसान नहीं है यदि आपको पूर्व-ईएस 6 ब्राउज़रों का समर्थन करने की आवश्यकता है। कुछ नोट्स के लिए नीचे देखें कि इसे कैसे लागू किया जा सकता है, लेकिन इस बीच मैं एक अपेक्षाकृत सरल दृष्टिकोण का सुझाव देता हूं जिसमें अन्य उत्तरों के साथ कुछ सर्वोत्तम सुझाव शामिल हैं:
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
सीधे सीधे इसे बढ़ाने की कोशिश किए बिना उपयोग करना सबसे अच्छा लगता है जो व्यावहारिक रूप से उस कोड के लिए किया जा सकता है जिसे गैर-ईएस 6 ब्राउज़रों का समर्थन करने की आवश्यकता होती है।
एक अन्य दृष्टिकोण है जो कुछ लोग विचार करना चाह सकते हैं, जो Object.setPrototypeOf()
कि एक त्रुटि वस्तु बनाने के लिए जहां उपलब्ध है उसका उपयोग करना है जो आपके कस्टम त्रुटि प्रकार का एक उदाहरण है, लेकिन जो कंसोल में मूल त्रुटि की तरह दिखता है और व्यवहार करता है ( बेन के उत्तर के लिए धन्यवाद) सिफारिश के लिए)। यहाँ मेरा दृष्टिकोण उस दृष्टिकोण पर है: 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)
}
}
मैं एक कदम पीछे ले जाऊंगा और विचार करूंगा कि आप ऐसा क्यों करना चाहते हैं? मुझे लगता है कि बिंदु अलग-अलग त्रुटियों से अलग तरीके से निपटना है।
उदाहरण के लिए, पायथन में, आप कैच स्टेटमेंट को केवल कैच तक सीमित कर सकते हैं MyValidationError
, और शायद आप जावास्क्रिप्ट में भी कुछ ऐसा ही करने में सक्षम होना चाहते हैं।
catch (MyValidationError e) {
....
}
आप जावास्क्रिप्ट में ऐसा नहीं कर सकते। केवल एक कैच ब्लॉक होना है। यदि आप इसके प्रकार को निर्धारित करने के लिए त्रुटि पर एक बयान का उपयोग करने वाले हैं।
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"; ...
यह जॉर्ज बेली के उत्तर पर आधारित है , लेकिन मूल विचार का विस्तार और सरलीकरण करता है। यह कॉफीस्क्रिप्ट में लिखा गया है, लेकिन जावास्क्रिप्ट में बदलना आसान है। विचार बेली की कस्टम त्रुटि को एक डेकोरेटर के साथ बढ़ाता है जो इसे लपेटता है, जिससे आप आसानी से नई कस्टम त्रुटियां बना सकते हैं।
नोट: यह केवल 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 (संदेश) के उपयोग कर सकते हैं
कंस्ट्रक्टर एरर कहे जाने के बाद प्रोटोटाइप को बदलकर हमें कॉलस्टैक और मैसेज सेट करने की जरूरत नहीं है
मोहसिन के पास ईएस 6 में एक बड़ा जवाब है जो नाम सेट करता है, लेकिन यदि आप टाइपस्क्रिप्ट का उपयोग कर रहे हैं या यदि आप भविष्य में रह रहे हैं जहां उम्मीद है कि सार्वजनिक और निजी वर्ग के क्षेत्रों के लिए यह प्रस्ताव पिछले चरण 3 को एक प्रस्ताव के रूप में स्थानांतरित कर दिया है और इसे बनाया है ECMAScript / जावास्क्रिप्ट के भाग के रूप में चरण 4 में तब आप यह जानना चाहते होंगे कि यह अभी थोड़ा छोटा है। स्टेज 3 वह जगह है जहाँ ब्राउज़र सुविधाओं को लागू करना शुरू करते हैं, इसलिए यदि आपका ब्राउज़र इसे समर्थन करता है तो नीचे दिया गया कोड काम कर सकता है। (नए एज ब्राउज़र v81 में परीक्षण किया गया कि यह ठीक काम करता है)। सावधान रहें हालांकि यह इस समय एक अस्थिर विशेषता है और इसका सावधानी से उपयोग किया जाना चाहिए और आपको हमेशा अस्थिर सुविधाओं पर ब्राउज़र समर्थन की जांच करनी चाहिए। यह पोस्ट मुख्य रूप से उन भविष्य के निवासियों के लिए है जब ब्राउज़र इस का समर्थन कर सकते हैं। समर्थन की जाँच करने के लिए MDN की जाँच करेंऔर क्या मैं उपयोग कर सकता हूँ ? यह वर्तमान में ब्राउज़र बाजार जो वहाँ लेकिन ऐसा नहीं है कि महान इसलिए यदि आप वास्तव में अब इसका उपयोग करना चाहते हैं और या तो इंतजार की तरह एक transpiler उपयोग करने के लिए नहीं चाहते हो रही है भर में 66% समर्थन मिला है कोलाहल या की तरह कुछ टाइपप्रति ।
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'
।