कस्टम अपवाद प्रकार


224

क्या मैं जावास्क्रिप्ट में उपयोगकर्ता-परिभाषित अपवादों के लिए एक कस्टम प्रकार परिभाषित कर सकता हूं? यदि हां, तो मैं इसे कैसे करूंगा?


3
खबरदार। 10 मिनट में जावास्क्रिप्ट के अनुसार यदि आप एक अनबॉक्स मूल्य को फेंकते हैं तो आपको स्टैक ट्रेस नहीं मिलेगा।
Janus Troelsen

अपवादों को कस्टम अपवाद बनाने की क्षमता प्रदान करता है और कुछ गुम अपवादों को प्रदान करता है, जिसमें तर्क और अपवाद जैसे डिफ़ॉल्ट रूप से लागू होते हैं।
स्टीवन वेक्सलर

जवाबों:


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 पुस्तक पूर्वावलोकन अनुभाग दिखाता है
orip

11
एक स्ट्रिंग विधि जोड़ने से यह जावास्क्रिप्ट कंसोल में अच्छी तरह से दिखाई देगा। इसके बिना यह दिखाता है: बिना पढ़ा हुआ # <ऑब्जेक्ट> इसे प्रदर्शित करने वाले स्ट्रींग के साथ, जैसे दिखाया गया है: बिना पकड़ा सिस्टम त्रुटि: त्रुटि का पता चला। कृपया सिस्टम व्यवस्थापक से संपर्क करें।
जेडीसी

11
यह आपको तब तक स्टैक के निशान की अनुमति नहीं देगा जब तक कि आप त्रुटि से प्राप्त न करें
ल्यूक एच।

आप केवल इस कस्टम त्रुटि के साथ काम करने के लिए कैच ब्लॉक के भीतर फ़िल्टर कैसे कर सकते हैं?
ओवरड्रिव

@overdrivr कुछ something catch (e) { if (e instanceof TypeError) { … } else { throw e; } }something या something catch (e) { switch (e.constructor) { case TypeError: …; break; default: throw e; }something की तरह है।
सैम बोसालिस

92

आपको एक कस्टम अपवाद बनाना चाहिए जो प्रोटोटाइप त्रुटि से विरासत में मिला है। उदाहरण के लिए:

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;

यह मूल रूप से फ़ायरफ़ॉक्स और अन्य ब्राउज़रों पर स्टैक के निशान को बढ़ाने वाली वृद्धि के साथ ऊपर पोस्ट किए गए विघटित का एक सरलीकृत संस्करण है। यह उन्हीं परीक्षणों को संतुष्ट करता है जो उन्होंने पोस्ट किए थे:

उपयोग:

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
एमएसएन वेबसाइट इस चेतावनी को कैच के बारे में बताती है: गैर-मानक यह सुविधा गैर-मानक है और एक मानक ट्रैक पर नहीं है। वेब का सामना करने वाले उत्पादन साइटों पर इसका उपयोग न करें: यह प्रत्येक उपयोगकर्ता के लिए काम नहीं करेगा। कार्यान्वयन के बीच बड़ी असंगतताएं भी हो सकती हैं और भविष्य में व्यवहार बदल सकता है।
लॉरेंस डॉल

40

हाँ। आप जो कुछ भी चाहते हैं उसे फेंक सकते हैं: पूर्णांक, तार, ऑब्जेक्ट, जो भी हो। यदि आप किसी वस्तु को फेंकना चाहते हैं, तो बस एक नई वस्तु बनाएं, जैसे आप अन्य परिस्थितियों में एक बनाएंगे, और फिर उसे फेंक देंगे। मोज़िला के जावास्क्रिप्ट संदर्भ के कई उदाहरण हैं।


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();
}

क्या यह संक्षिप्त उदाहरण ठीक उसी तरह से काम नहीं करेगा, भले ही आपको एरर का प्रोटोटाइप विरासत में नहीं मिला हो? यह मेरे लिए स्पष्ट नहीं है कि इस उदाहरण में आपको क्या हासिल है।
ग्यारहवें

1
नहीं, e instanceof Errorझूठ होगा।
मॉर्गन एआरआर एलन

वास्तव में। लेकिन चूंकि e instanceof MyErrorयह सच होगा, else if(e instanceof Error)बयान का मूल्यांकन कभी नहीं किया जाएगा।
इलेवनटाइन 19

ठीक है, यह सिर्फ एक उदाहरण है कि यह शैली कैसे आज़माएगी / पकड़ लेगी। else if(e instanceof Error)आखिरी कैच कहां होगा। इसके बाद एक सरल else(जिसका मैंने समावेश नहीं किया)। तरह का क्रमबद्ध default:एक स्विच बयान में लेकिन त्रुटियों के लिए।
मॉर्गन ARR एलन

15

संक्षेप में:

विकल्प 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) {
      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 ढांचे का उपयोग करें

स्पष्टीकरण:

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

11

यहां बताया गया है कि आप मूल Errorव्यवहार के साथ पूरी तरह से कस्टम त्रुटि कैसे बना सकते हैं । यह तकनीक अभी के लिए केवल क्रोम और नोड.जेएस में काम करती है । अगर आप यह नहीं समझते हैं कि मैं इसका इस्तेमाल करने की सलाह नहीं दूंगा।

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)है काम करने के लिए नहीं निर्दिष्ट । मेरा सुझाव है कि स्टैक ट्रेस को कॉपी करना है जो क्रॉस-ब्राउज़र संगत है।
कोर्नेल

11

मैं अक्सर प्रोटोटाइप विरासत के साथ एक दृष्टिकोण का उपयोग करता हूं। ओवरराइड करने toString()से आपको यह फायदा होता है कि फायरबग जैसे उपकरण [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

फेंक कथन का उपयोग करें ।

जावास्क्रिप्ट परवाह नहीं करता है कि अपवाद प्रकार क्या है (जैसा कि जावा करता है)। जावास्क्रिप्ट सिर्फ नोटिस, एक अपवाद है और जब आप इसे पकड़ते हैं, तो आप "अपवाद" कहते हैं "देख सकते हैं"।

यदि आपके पास अलग-अलग अपवाद प्रकार हैं जिन्हें आपको फेंकना है, तो मैं उन चर का उपयोग करने का सुझाव दूंगा जिनमें अपवाद / संदेश का स्ट्रिंग / ऑब्जेक्ट शामिल है। जहां आपको इसकी आवश्यकता है "थ्रो माय एक्ससेप्शन" का उपयोग करें और कैच में, कैप्शन को माई एक्ससेप्शन से तुलना करें।


1

एमडीएन में इस उदाहरण को देखें ।

यदि आपको कई त्रुटियों को परिभाषित करने की आवश्यकता है ( यहां कोड का परीक्षण करें !):

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;

कोड ज्यादातर से कॉपी किया जाता है: जावास्क्रिप्ट में त्रुटि को बढ़ाने का एक अच्छा तरीका क्या है?


1

ES2015 वर्गों के साथ उपयोग के लिए एसेलिन के उत्तर का एक विकल्प

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;
    }
}

अब हम कारण या जो भी गुण चाहते हैं, उसे त्रुटि ऑब्जेक्ट में जोड़ते हैं और इसे पुनः प्राप्त करते हैं। त्रुटि को और अधिक उचित बनाकर।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.