I was recently told not to declare my variables inside an if block.
if (condition) {
var foo = { bar: 'abcd' };
}
//bunch of code.
However, JavaScript does not have scope blocking. I understand that if the condition is not true, foo is going to be null and doing something like foo.bar later in the code is going to throw me cannot read bar of undefined error.
That being said, is it wrong to do what I did going by ES6 specs?
Additionally to what Kleo wrote, I recommend using the 'use strict'; strict mode, if ES6 is not available, which helps improve code quality and reduce undefined bahvior. One of the things it forbids is using undeclared variables.
Strict mode changes both syntax and runtime behavior. Changes generally fall into these categories: changes converting mistakes into errors (as syntax errors or at runtime), changes simplifying how the particular variable for a given use of a name is computed, changes simplifying
evalandarguments, changes making it easier to write "secure" JavaScript, and changes anticipating future ECMAScript evolution.
(from MDN)
The spec is not going to forbid using var the way you did.
It's a matter of preference.
I prefer my vars declared right around where they're used, and definitely within the same block.
Before JS got block-scoped variables with "let", the advice to not declare vars inside blocks may have made sense, since doing so would give other developers the wrong idea about the vars' scope.
But now, I would go ahead and keep the declaration (using let, not var) inside the if block.
PS: foo is going to be undefined, not null, if the condition is false; null !== undefined
There is nothing wrong with declaring a variable inside an if-statement block. However, if you're writing ES6 you should consider dropping var from your vocabulary. Use let and const instead (these do follow more logical scoping rules -- whereas var in your case would be scoped to the containing function)
foo is indeed going to be undefined, unless the condition is met, but it won't throw any exceptions, you'll just get an undefined value if you use foo in any expression. In your example it is a matter of better style: you're declaring a variable inside of if block, but plan to use it outside. Sure, it'll be hoisted and created anyway, but it just makes code less explicit and less readable. In this case it's indeed better to declare it at the top of function.
I won't comment on how ES6 let and const work, as other people already described that. Instead I'd like to note, that if you find yourself writing functions with multiple blocks, each using it's own multiple block-scoped variables, I'd strongly suggest splitting your function into smaller functions with descriptive names. That will make your code so much more readable. Having let and block scope is nice, but it doesn't mean you should always use them. :)
Siddarthan Sarumathi Pandian
Full Stack Dev at Agentdesks | Ex Hashnode | Ex Shippable | Ex Altair Engineering
Kleo Petrov
Professional human being for 29 years
foo is going to be null- foo is going to beundefinedin your case, because the variable will be hoisted.ES5 is function scoped and not block scoped, meaning the following code:
function foo() { if (true) { var bar = 'Hello World'; } return bar; } foo();will output
Hello World. What is actually happening? - Before executing the above code, the variables and functions are stored in memory. They are not physically moved at the top of the function! This means that before execution, the body of the function foo and the variable bar, without its value will be stored in memory. This is what hoisting actually does.When the execution of the code starts, the JavaScript interpreter already has access to
foo()andbar(bar is assigned the value ofundefined). When the execution reaches line 3 -var bar = 'Hello World';, JavaScript simply assigns a new value to the variable bar - in our case the right side of the assignment -Hello World. At first it seems thatvar bar = 'Hello World';is one statement, but are actually two separate statements -var bar;andbar = 'Hello World'.Let's transform our example to ES6:
function foo() { if (true) { const bar = 'Hello World'; } return bar; } foo();This code will throw with a ReferenceError -
ReferenceError: bar is not defined. This is becauseconstandlet, the two new variable types is ES6, are block scoped.Block statement, also known as compound statement is a group of zero or more statements, wrapped in curly brackets:
{ } // empty block statement { const message = 1; } // non empty block statementSo, if we have the following code:
const exam = 'passed'; if (true) { const exam = 'failed'; } console.log(exam); // 'passed'The output will be
passed, because the code has two scopes - the "global" scope, where the variableconst exam = 'passed'lives and the block scope, where the variableexamis assigned the valuefailed. Although looking pretty similar, they are two distinct variables.So, my rule of thumb is to use
constwhenever possible,letif I need to change the value of the variable at a latter state and forget aboutvar.Variable initialization inside if statement is error prone and kind of makes me uncomfortable. Lets say you have a fairly big function, where you assign a value to a variable, forget about it and reassign it again in an if statement. The chance of assigning the wrong value is very high. Another reason why I'm against this is because it hardens readability and debugging. My personal preference is to store all function variables at the top of the function, instead being spread across the whole function body.