In the current Chrome, if I do this:
var i = 'foo';
i();
I get an error 'string is not a function'. I get similar errors if i is a number, undefined, etc.
However, from some real-life, more complex code, sometimes I see a different error:
'expected function: function(){}'
I am trying to figure out exactly how these two errors differ, or, to look at it another way, how to write a minimal code snip that will trigger the 'expected function' error.
I tried fiddling with callbacks, and call/apply, but none of those trigger this. Can anyone explain how to reproduce this error?
There is no specification what error message should be. Therefore each vendor implements it's own. The only way to unify this is to verify data yourslef and throw error that you expect.
var i = 'foo';
if (!$.isFunction(i)){
throw 'expected function: function(){}';
}
Related
I'm a JS game dev who's been trying to combat tampermonkey scripts for a while now.
I came up with a solution for people hooking into WebSockets where I'd cause the WebSocket to throw an error new WebSocket(0); (0 throws an error due to it being a number)
let output;
try {
output = new target(...args);
} catch(e) {
let source = e.stack.substring(e.stack.indexOf("("), 1 + e.stack.indexOf(")"));
e.stack = e.stack.replace(source, "nothing to see here");
throw e;
}
this code made the error's stack have all the information I was looking for replaced!
I've been looking at Object.defineProperty, and I was wondering how I could stop an error's stack from being modified before I have access to that specific error. And if anyone has any other ways I could stop a script from being loaded or run, I'd love to hear them!
One thing you could do is Object.freeze the error before throwing it. This would prevent people from altering the object's contents.
So for example:
try {
new WebSocket(0);
} catch (wsErr) {
throw Object.freeze(wsErr);
}
The code catching your error and trying to alter it would fail to be able to alter it. This should work as it will cause the code that was altering the error to throw with the following:
Cannot assign to read only property 'stack' of object ''
The other thing you'll have to consider is that in your code where you're catching the error, you will not be able to alter its contents either. Typically with errors, that's not a huge deal though. Tampering with errors is one of the only reasons I can think of for modifying the error.
I'm guessing the answer to my question is no, but since I don't know enough about how Error.prototype works I figured it was worth asking: is there any way to change the error messages from the errors in Javascript?
For instance, if I get an error:
TypeError: (intermediate value) is not iterable
is there any way to change things such that I instead get:
TypeError: You expected an array but it wasn't an array dummy!
I thought about using a global error handler and then rethrowing them, but that would only work for uncaught errors. Is there any Error.prototype method I can change (or any other way) to do this?
Not at all important, just curious.
EDIT: Just to clarify two points:
1) I understand how try/catch works, but what I'm asking about is whether there is a way to control the messages generated before the error is thrown/caught (presumably by overwriting a method of Error.prototype).
2) An answer of "no there is no way to do this, all generating of JS error messages is handled internally and the JS code has no way to control it" would be perfectly legitimate (... if that's the case).
You have to override the TypeError class, not one of these methods.
const overridableMessages = [{
search: 'TypeError: (intermediate value) is not iterable',
replace: 'TypeError: You expected an array but it wasn\'t an array dummy!'
}]
class TypeError extends window.TypeError {
constructor (message) {
super(message)
overridableMessages.forEach((overridableMessage) => {
if (this.message === overridableMessage.search) {
this.message = overridableMessage.replace
}
})
}
}
window.TypeError = TypeError
window.onerror = function(msg, url, linenumber) {alert('Error : '+msg+'\nURL: '+url+'\nLine Number: '+linenumber);return true;}
// general error handler
Also:
try {
}
catch(err) {
alert(err); // here put your case with your messages.
}
// routine error handler
HIH,
I hate to answer my own question, but I found this line on the MDN which seems to pretty clearly answer things:
The global Error object contains no methods of its own, however, it does inherit some methods through the prototype chain.
Since the only methods it gets through the prototype chain are toString and toSource (neither of which controls an error's generated message), it appears (unless I'm missing some other mechanism that isn't Error.prototype-related) that there is no way to accomplish what I asked.
JavaScript, when throw-ing a built-in error as such:
throw new Error("Something was wrong");
displays the text nicely - you can't tell you threw an object
However, when creating a custom error by subclassing the Error object (or other error object for that matter), the thrown error is not displayed the same way in the console.
So, by using this code:
var ImproperlyConfigured = function(message){
this.name ="ImproperlyConfigured";
this.message = message || "The object you tried to construct was improperly configured due to an unknown error";
}
ImproperlyConfigured.prototype = new Error();
The following is the output
I don't like the fact that the object properties (name and message) are shown. In fact, I don't like that I don't understand why the properties are shown.
I've googled a bit and I got the feeling that by implementing a toString method will help but, by using this method, the fact that the name of the error is no longer in red puzzles me even more.
Code
var ImproperlyConfigured = function(message){
this.name ="ImproperlyConfigured";
this.message = message || "The object you tried to construct was improperly configured due to an unknown error";
this.toString = function(){
return this.message;
}
}
ImproperlyConfigured.prototype = new Error();
Output:
What I would like to achieve is a standard looking error, by the use of custom error and, of course, by not using the console.error method manually in a try...catch block.
Is this possible?
As Pointy correctly pointed out (pun intended), the issue here is not with JavaScript, but rather with the environment JavaScript is running (in this case, Google Chrome).
In another environment (like Chromium, Firefox, NodeJS, etc.) the behavior will likely be different, using the same code, depending on how those JavaScript hosts are handling these cases.
I would like to check if a certain console error has occurred using javascript, and alert() myself if it has.
The error will look like this:
00:00:34:0359 TimeEvent.COMPLETE
(anonymous function) # VM17617:1
And the algorithm will look something like this:
function checkError(console) {
if(console.error === "TimeEvent.COMPLETE") {
alert("The error is present");
}
}
I'm not very familiar with the console, and haven't gotten much further with Google research. Can somebody point me in the right direction?
I ultimately solved my question by following this blog post on taking over the console with javascript.
Here is my final code:
var original = window.console
window.console = {
error: function(){
//Gets text from error message.
errorText = arguments['0'];
if (errorText.includes('TimeEvent.COMPLETE')) {
//DO STUFF HERE
}
original.error.apply(original, arguments)
}
}
You didn't provide the whole picture about how and when the console is getting the error. If you raise the error yourself, or if you are able to catch it inside a try catch, that would be the best place to intercept those errors.
However, if you have no control about how those error are raised, you should try to intercept your console's error calls. I never tried it myself but this SO answer explains how to intercept the console's log calls. Knowing that the console usually have a function named error that is similar to the log function, I'm sure you could apply the same logic to intercept the errors sent to the console.
If you are using chrome, you may refer to the console documentation for more details about the error function. I'm not sure if there's a standard butInternet Explorer and Firefox also has support for console error function.
UPDATE
[Rewriting question to focus on the problem I am trying to understand.]
Is there a means in JavaScript to throw Exceptions that notify the line number where the problem occurs? Similar to C#'s debugger, if an error is thrown on line 50 then I will be taken to line 50.
For example, according to MDN EvalError represents an error with eval(). So, let's say I have a function that uses eval(). I want to use a specific error that is representative of the problem at hand, EvalError:
//As written here the error implies there is a problem on this line. See Firebug console window
var evalErra = new EvalError('required element missing from evaluation');
var stringFunc = "a=2;y=3;document.write(x*y);";
EvalString(stringFunc);
function EvalString(stringObject) {
//Some arbitrary check, for arguments sake let's say checking for 'x' makes this eval() valid.
if(stringObject.indexOf('x') !== -1) {
throw evalErra;
//throw 'required element missing from evaluation';//This way offers no line number
}
eval(stringFunc);//The problem really lies in the context of this function.
}
If I'm going about this all wrong, then please tell me how I should approach these kinds of issues.
When you throw an error, execution of the current code will stop and JS will work its way back up the execution tree until it finds a catch () which handles the particular type of error being thrown, or gets all the way up to the top of the tree, causing an "unhandled exception" error: You threw an error, and nothing caught it, and now someone's window got broken.
try {
if (true) {
throw 'yup'
}
} catch (e) { // catches all errors
... handle the error
}
When doing error handling you want to do the following
throw new Error("message");
Then if you ever handle this error look at err.stack (firefox/opera/chrome) or err.line (Safari) or err.IE_Y_U_NO_SHOW_ME_ERROR_LINE_NUMBER (IE) to find the line number.
If you want you can subclass Error.