Const behaviour if require fails - javascript

Opening the node repl (v6.6.0) and doing:
> const test = require('somethingGuaranteedToFail');
Error: Cannot find module 'somethingGuaranteedToFail'
Now the variable test can neither be redefined, nor has it been properly initialized.
> console.log(typeof test);
ReferenceError: test is not defined
> const test = 1;
TypeError: Identifier 'test' has already been declared
It seems to happen with anything that throws an error during assignment, not just require.
I guess the question is, is this expected behaviour? I would have thought the const variable would at least contain the Error object.

I guess the question is, is this expected behaviour?
Yes. A const cannot be redefined or redeclared. const test declared it, but failed to define it because an error was raised.
I would have thought the const variable would at least contain the Error object.
require does not return an error, it throws one. If you want it, you need to catch it.

Yes, this is expected the behavior. If you throw an exception, the test variable will never initialize. This is also the case for something like
var getTest;
try {
getTest = function(){
return test;
};
throw new Error();
const test = 'a string';
} catch (e){
// ignore the error
}
getTest();
The final call to getTest will attempt to access test, which was never initialized because the exception caused the string value to never be assigned. It will never be assigned the Error object, because the initialization of test is unrelated to the exception.

I don't know if this is a bug, but regardless of whether it's intended or not, this behavior can only occur in a REPL environment.
The reason is that, unlike var, const is block-scoped, but if you try to assign the result of a require statement that throws an exception to it (e.g., when the module resolution fails), an exception will be thrown and execution will leave the scope of the block, so the variable falls out of scope. Since you can't stay in the same scope as the variable is defined after an exception is thrown, you cannot redefine a new const variable in the same scope.
However, in the REPL environment, you don't leave the same scope when an exception fails, therefore you can end up in a situation where a failed const declaration is still in scope, so node refuses to redeclare it.

Related

Variable throws initialization error after initializing it

I'm trying to make a Discord bot, one of its features is that it plays chess, at the start of the command, I read the JSON file, then check if it's undefined since I'll call a key from the object, so just in case it doesn't exist already, I'll create the data needed
Problem is, when I try to assign the data, it says I haven't initialized the variable, which is weird, because I did initialize it 3 lines before, var, let and const all throw the same error
Another thing is that outside the if statement, just above it, when console.logging it, it works perfectly, but when console.logging it inside the if statement, it throws that error
I honestly have no idea what's happening here, I can't think of anything that's causing this either, is this a NodeJS bug? I feel like it could be.
const games = JSON.parse(fs.readFileSync("./lib/database/games/chess/chess_games.json"))
console.log(games, 'outside if statement') // Here it outputs just fine
if (games[interaction.guild.id] == undefined) {
console.log(games, 'inside if statement') // Here is where it breaks
games[interaction.guild.id] = {
games: {},
players: {},
amount_of_games: 0
}
fs.writeFileSync("./lib/database/games/chess/chess_games.json", JSON.stringify(games, null, 2));
const games = JSON.parse(fs.readFileSync("./lib/database/games/chess/chess_games.json"))
}
This is the error:
ReferenceError: Cannot access 'games' before initialization
at Object.execute (C:\Users\aschr\Dropbox\Coding\Javascript\entropic_bot\lib\database\bot\commands\chess.js:40:4)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Client.<anonymous> (C:\Users\aschr\Dropbox\Coding\Javascript\entropic_bot\index.js:44:3)
You have two variables with the same name.
Change the name of one of them
The second games is tried to be accessed instead of the first one because of hoisting. That's why you are getting the error

ESlint rule that detects that a variable and a function has the same name in Javascript?

I happened to name a variable the same as a function in Node.js. This did not go very well, Node 10 did not like it. And since this was a hook function (not called from the UI of the app) it took some time before I discovered what went wrong.
Is there some ESLint rule that can discover these type of bugs? This is under Firebase and and ESLint is run during the deploy to production server.
The actual conflicting use of the variable name was in the same block, something like this: const a = a(x).
I don't think a tool like this could exist for JavaScript, as JavaScript doesn't really disambiguate the type of object assigned to the variable.
function a() {
}
... is basically equivalent to:
var a = function () {
};
Additionally, the value of a in this example can be reassigned later.
A linter may help you, and there may be some help in some IDEs, but they won't truly know the intention of the programmer.
There is a no-redeclare rule you can set in ESLint, which tells you the problematic line in your code.
/*eslint no-redeclare: "error"*/
function a() {}
const a = a();
=> 4:5 error 'a' is already defined no-redeclare
Also ESLint will raises an error with the standard configuration.
function a() {}
var a = a();
=> 4:5 error Parsing error: Identifier 'a' has already been declared
Of course, with const, you will get a syntax error with the line as well if you try to run your script.

Jasmine Unit Tests Unexpected this Reference

I am trying to test a fairly simple JavaScript function in Jasmine, however the first statement is throwing an error for being undefined.
myClass.prototype.functiontoBeTested = function() {
var x = this.method()
...
}
The above throws an error in Jasmine as method is not a function and is undefined. The prototype is altered earlier to have this method, and out of curiosity I assigned this method to my test object in the spec itself as such:
myObject.method = function(){return mockResults;};
So I decided to log this to the console and instead of it being my object, I see Window {top: Window, location: Location, document: document, window: Window, external: Object…} which doesn't seem right. I've had this issue before with testing a function in Jasmine that used this but just changed the source code to refer to the object by name since the function was being assigned to something within the closure. I can't do that in this case, and I'm curious why this is referring to something unexpected (at least to me).
Edit: Some details on what the test case looks like as requested:
it("updates the control count", function(){
var mockResults = { ... };
myObject.method = function() {return mockResults;};
expect(myObject.method).not.toThrow();
});
Right now I'm just trying to get the method to execute to completion during the test. The function to be tested updates the text on some HTML components, I'll work on verifying those once I can get it to actually run. The method that is causing an error is the first line of the function, and is simply an accessor method for the object being called. In actual execution, var x = this.method() runs without issue. When testing in jasmine var x = this.method() throws an error because method() is undefined for this. Instead of this referring to the calling object, it is referring to the window. This doesn't happen live, but only during testing with Jasmine. This method is undefined even when I forcibly define it for the test object just prior to execution in the test as above. That's when I decided to log this to console in the source code and realized it isn't referring to what I would have expected it to refer to.
In JavaScript this for a method depends on the context it was called from. When you do a call myObject.method(), then method was called from the context of myObject, therefore this is myObject.
When you pass your function to Jasmine toThrow matcher, it calls it as it was passed (see source code):
try {
actual();
} catch (e) {
// ....
}
Here, actual() is a call of your method. It has no any specific context, so by default it will be called from window context.
Solution is to explicitly bind you method to myObject like the following:
expect(myObject.method.bind(myObject)).not.toThrow();
Credits to questions, you can find more details there:
Does Jasmine's toThrow matcher require the argument to be wrapped in an anonymous function?
How to write a test which expects an Error to be thrown in Jasmine?

Can I throw an exception in Javascript, that stops Javascript execution?

I try to simulate a problem where a script that is loaded from an external url stops execution of any more scripts on my site.
I tried to simulate such a problem by calling a function that does not exits. I can see the error in firebug but different scripts on the page are still executed.
Are there different kinds of errors in Javascripts? If yes: what kind of error stops script execution? I only need this answer for Firefox.
EDIT
This question is easy to misunderstood but Rob W got it: I need to throw an exception and that exception needs to stop further script execution.
Answer to the title: No
Answer to "Are there different kinds of errors in JavaScript**: Yes, see MDN: Error
Syntax errors will prevent a whole script block from being executed,
other errors (TypeErrors, Reference errors) will only stop the execution after the occurrence of the error.
Different <script> blocks are executed separately. You cannot prevent the second block from execution by throwing an error in the first block (Demo: http://jsfiddle.net/WJCEN/).
<script>Example: Syntax error in this script.</script>
<script>console.log('Still executed.')</script>
Also, if an error is caught using try-catch (demo: http://jsfiddle.net/WJCEN/1/), then the error will not even stop the execution a whole block.
try {throw 'Code';}catch(e){}
console.log('Still executed');
There is no general one-fit-all method to stop all code from running. For individual scripts, you can use some tricks to prevent the code from running further.
Example 1 (demo): Temporary overwrite a method
1: <script>window._alert = alert;alert=null;</script>
2: <script>alert('Some code!');confirm('Not executing');</script>
3: <script>alert=_alert;delete window._alert;alert('Done!');</script>
This method is based on the fact that script 2 expects alert to be a function. We have rewritten alert to a non-function property (script 1). Script 2 throws a TypeError, and the second block is skipped.
We restore the original values in script 3.
Example 2 (demo): Define a constant method, which cannot be overwritten.
4. <script>Object.defineProperty(window, 'test',{value:null});</script>
5. <script>var test=function(){alert('Test');};test();alert('What?');</script>
This methods relies on the Object.defineProperty method, to effectively define a constant value. In strict mode, the var test declaration would throw a TypeError: "test is read-only".
When strict mode is not enables, a TypeError will be thrown at test(): "test is not a function" (because we defined test to be constant, in script 4).
Note: The last method is not working correctly with function declarations (see bug #115452, Chrome 17)
Use
try catch finally block
It will do the trick
you can use the error object which support the following two properties:
name: The name of the error.
message: A description of the error.
for example to stop execution you can use : throw new Error("myError");
Are there different kinds of errors in Javascripts?
Besides the generic Error constructor, there are six other core errors in JavaScript:
see here details on these errors.
Stop the execution with
throw new Error('stopIt');
This will also do the trick:
throw 'Stop It!';

How to create, design and throw built-in Error objects

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.

Categories

Resources