最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

dom - ManuallyArtificially throwing a DOMException with JavaScript - Stack Overflow

programmeradmin1浏览0评论

Is it possible to manually throw a DOMException error in pure JavaScript? Documentation I've read suggests it should be relatively easy to construct (at least in Java.)

However, in Chrome, following code returns TypeError: Illegal constructor:

// DOM SYNTAX_ERR (12)
var myDOMException = new DOMException(12,"I'm sorry Dave, I'm afraid I can't do that.");

Regrettably, this is what I expected after reading the W3 docs, which don't appear to specify a constructor at all. (As an aside, while I'm not particularly 'au fait' with IDL, I would have assumed their variant would support specification of constructors.)

Frustratingly, the DOMException class lurks tantalisingly in the global scope. How can I use it? Can I use it?

Update

Since I wrote this, I've made a couple of discoveries - namely:

var myDOMException = DOMException.constructor(12,"Error Message");
var myDOMException2 = DOMException.constructor.call(DOMException,DOMException.SYNTAX_ERR,"Error Message");

Looks like it worked!

...not so fast.

$> myDOMException instanceof DOMException
false
$> myDOMException2 instanceof DOMException
false

And possibly even more offputting:

$> myDOMException.constructor
function Number() {
    [native code]
}

As always, any assistance would be greatly appreciated.

Update #2

Just to clarify my reasons for returning a DOMException object as opposed to a more generic Error - I'm trying to implement the WHATWG's Timed Text Track spec in pure JavaScript. There are a number of instances where a proper solution would be required to return a DOMException object, specifically one with a code of 12 (SYNTAX_ERR.)

Is it possible to manually throw a DOMException error in pure JavaScript? Documentation I've read suggests it should be relatively easy to construct (at least in Java.)

However, in Chrome, following code returns TypeError: Illegal constructor:

// DOM SYNTAX_ERR (12)
var myDOMException = new DOMException(12,"I'm sorry Dave, I'm afraid I can't do that.");

Regrettably, this is what I expected after reading the W3 docs, which don't appear to specify a constructor at all. (As an aside, while I'm not particularly 'au fait' with IDL, I would have assumed their variant would support specification of constructors.)

Frustratingly, the DOMException class lurks tantalisingly in the global scope. How can I use it? Can I use it?

Update

Since I wrote this, I've made a couple of discoveries - namely:

var myDOMException = DOMException.constructor(12,"Error Message");
var myDOMException2 = DOMException.constructor.call(DOMException,DOMException.SYNTAX_ERR,"Error Message");

Looks like it worked!

...not so fast.

$> myDOMException instanceof DOMException
false
$> myDOMException2 instanceof DOMException
false

And possibly even more offputting:

$> myDOMException.constructor
function Number() {
    [native code]
}

As always, any assistance would be greatly appreciated.

Update #2

Just to clarify my reasons for returning a DOMException object as opposed to a more generic Error - I'm trying to implement the WHATWG's Timed Text Track spec in pure JavaScript. There are a number of instances where a proper solution would be required to return a DOMException object, specifically one with a code of 12 (SYNTAX_ERR.)

Share Improve this question edited Feb 27, 2011 at 23:55 Christopher asked Feb 27, 2011 at 23:09 ChristopherChristopher 5344 silver badges11 bronze badges 7
  • 4 Java and JavaScript are like car and carpet (to quote this answer). So that documentation is irrelevant. – Matthew Flaschen Commented Feb 27, 2011 at 23:14
  • I was more interested in it as a DOM implementation, not as a 'similar to JavaScript' language, which I'm well aware it's not (name aside.) – Christopher Commented Feb 27, 2011 at 23:21
  • If you would elaborate on why you want to be able to throw such a thing, you might get some interesting suggestions. – Pointy Commented Feb 27, 2011 at 23:27
  • @Pointy Thanks - see my revised question above. – Christopher Commented Feb 27, 2011 at 23:37
  • Internal objects do lots of weird things and break tons of rules. The reason calling DOMException.constructor works is because the proto for a DOMException isn't a function as normal constructors are, it's an object, even though the object signature is a function (don't ask me why). Also, normally, the constructor property will always be functions, because anything you instantiate is a function. The place you want to find the proper constructor for an object is within prototype.constructor, which will almost always point back at the object that contains the prototype, unless you override it. – TimE Commented Dec 4, 2012 at 11:47
 |  Show 2 more comments

3 Answers 3

Reset to default 12

In Firefox, at least, DOMException is not a function. It is an object that defines several constants.

 typeof DOMException === 'object' // true (not 'function')

It could be used like this:

try {
    throw DOMException;
} catch(e) {
    if (e === DOMException)
        console.log("caught DOMException")
}

This works if you're trying to signal a DOMException but don't need an actual instance of DOMException.

Ugly, ugly hack (that basically works)

If you absolutely need an instance of DOMException that has the SYNTAX_ERR code, you could perform an action that causes one to be created and throw that:

function createSyntaxException() {
    try {
        // will cause a DOMException
        document.querySelectorAll("div:foo");
    } catch(e) {
        return e;
    }
}

throw createSyntaxException();

The details of the thrown exception won't match your specific situation, of course, but the resulting object will have the correct code and pass instanceof checks.

var e = createSyntaxException();
console.log(e instanceof DOMException); // true
console.log(e.code === e.SYNTAX_ERR); // true

You could mitigate the details issue by subclassing DOMException and adding getters/setters for each of its (read-only) properties.

function DOMExceptionCustom() {
    var message;
    this.__defineGetter__("message", function(){
        return message;
    });
    this.__defineSetter__("message", function(val){
        message = val;
    });
}

// subclass DOMException
DOMExceptionCustom.prototype = createSyntaxException();

var err = new DOMExceptionCustom();
err.message = "my custom message";

The resulting object has the desired properties:

console.log(err.code === err.SYNTAX_ERR); // true
console.log(err.message); // "my custom message"
console.log(err instanceof DOMExceptionCustom); // true
console.log(err instanceof DOMException); // true

Here is my crack at it. Solution based on ECMAScript 5 and WebIDL. I've discussed this with the W3C/ECMAScript join task force that are working on WebIDL. They said it's basically impossible to do because it relies on internal platform behaviour... but here is something that may be close enough.

function CustomDOMException(code, message) {
    //throw on missing code
    if (typeof code !== "number") {
        throw TypeError("Wrong argument");
    }

    //we need the codes, to get the "name" property.  
    var consts = {
        1: "INDEX_SIZE_ERR",
        3: "HIERARCHY_REQUEST_ERR",
        4: "WRONG_DOCUMENT_ERR",
        5: "INVALID_CHARACTER_ERR",
        7: "NO_MODIFICATION_ALLOWED_ERR",
        8: "NOT_FOUND_ERR",
        9: "NOT_SUPPORTED_ERR",
        11: "INVALID_STATE_ERR",
        12: "SYNTAX_ERR",
        13: "INVALID_MODIFICATION_ERR",
        14: "NAMESPACE_ERR",
        15: "INVALID_ACCESS_ERR",
        17: "TYPE_MISMATCH_ERR",
        18: "SECURITY_ERR",
        19: "NETWORK_ERR",
        20: "ABORT_ERR",
        21: "URL_MISMATCH_ERR",
        22: "QUOTA_EXCEEDED_ERR",
        23: "TIMEOUT_ERR",
        24: "INVALID_NODE_TYPE_ERR",
        25: "DATA_CLONE_ERR"
    }
    if ((code in consts) === false) {
        throw TypeError("Unknown exception code: " + code);
    }

    //props for adding properties
    var props = {};
    //generate an exception object 
    var newException;
    try {
        //force an exception to be generated; 
        document.removeChild({})
    } catch (e) {
        //use it as the prototype  
        newException = Object.create(Object.getPrototypeOf(e));
    }
    //get the name of the exception type        
    var name = consts[code];

    //add the properties
    var props = {value: null, writable: true, enumerable: false, Configurable: true};
    //name
    props.value = name; 
    Object.defineProperty(newException, "name",    props);
    props.value = code; 
    Object.defineProperty(newException, "code",    props);
    props.value = message; 
    Object.defineProperty(newException, "message", props);

    //Make sure it "stringifies" properly 
    var finalMessage;
    var obj = this;
    if (typeof message === "function") {
        finalMessage = function() {
            return message.call(newException)
        }
    } else {
        finalMessage = function() {
            return name + ": DOM Exception " + code;
        }
    }
    props.value = function() {
        return finalMessage.call(newException)
    }

    Object.defineProperty(newException, "toString", props);
    return newException;

}

And some tests:

// Throws SYNTAX_ERR    
console.log(new CustomDOMException(12)); 

// Custom message 
console.log(new CustomDOMException(1, "ERROR!")); 

// Custom message 
console.log(new CustomDOMException(1, function() {
    return "Custom Err:" + this.name + " : " + Date.now()
}));

// Throws TypeError     
try {
    new CustomDOMException(2)
} catch (e) {
    console.log(e);    
}

// Throws TypeError
try {
    new CustomDOMException()
} catch (e) {
    console.log(e);    
}    

// Throws TypeError    
try {
    new CustomDOMException("Wee!")
} catch (e) {
    console.log(e);    
}

//Check the inheritance chain     
var ext = new CustomDOMException(17);
var isInstance = ext instanceof DOMException;
console.log("instanceof DOMException: " + isInstance)​

Although it is an old question,

I have found out the correct way to do it. So I share it here.

  • error.code is meaningful but cannot be used for error construction.
  • error.code will automatically match the error.name e.g. TimeoutError, AbortError, TypeError, etc.

As you want to error to have the error.code = DOMException.SYNTAX_ERR (12), you can use document.querySelector('a::b') to create that error and find out its error name.

Then you can have

throw new DOMException("I'm sorry Dave, I'm afraid I can't do that.", "SyntaxError")

You can also change DOMException to MyOwnError.

    class MyOwnError extends DOMException{
        constructor(msg){
            super(msg, 'SyntaxError');
        }
    }
throw new MyOwnError("I'm sorry Dave, I'm afraid I can't do that.", "SyntaxError")

class MyOwnError extends DOMException {
  constructor(msg) {
    super(msg, 'SyntaxError');
  }
}

const err = new MyOwnError("Oops...")
console.log(err.code === err.SYNTAX_ERR); // true
console.log(err.message); // "my custom message"
console.log(err instanceof MyOwnError); // true
console.log(err instanceof DOMException); // true
throw err

发布评论

评论列表(0)

  1. 暂无评论