Here is some sample code. I'd like to know if there is any reason why I shouldn't do this.
//some code
var x = "hello";
{
var y = "nice";
function myfunction() {
//do stuff . . .
}
}
The benefit of doing this I see is being able to organize sections of code in chunks and have auto formatters do some work with that...
In my tests {} does not affect the scope when creating a var or function.
This answer was written in times of earlier JavaScript implementations. While the same rules for var apply, ECMAScript 2015 (aka ES6) introduce the let variable declaration statement, which follows "traditional" block-scoped rules.
Example of let scoping with a Block, which logs "1", "2", "1":
{ let x = 1; console.log(x); { let x = 2; console.log(x) }; console.log(x) }
The MDN Reference on Block summarizes the usage of blocks as:
Important: JavaScript does not have block scope. Variables introduced with a block are scoped to the containing function or script, and the effects of setting them persist beyond the block itself. In other words, block statements do not introduce a scope. Although "standalone" blocks are valid syntax, you do not want to use standalone blocks in JavaScript, because they don't do what you think they do, if you think they do anything like such blocks in C or Java.
As discussed on MDN, the syntax is perfectly valid as { StatementList } (aka Block) is a valid Statement production..
However; and because this is very important: a new block does not introduce a new scope. Only function bodies introduce new scopes. In this case, both the x and y variables have the same scope.
In addition a FunctionDeclaration should appear only as a top-level statement - that is, it must be a statement directly under a Program or Function body, not a Block. In this case the declaration of myfunction is "not reliably portable among implementations".
There is the IIFE (Immediately Invoked Function Expression) pattern which can be used and, while it addresses the technical issues above, I would not recommend it here as it complicates the code. Instead, I would simply create more named functions (named functions can be nested!), perhaps in different modules or objects, as appropriate.
var x = "hello";
;(function () {
// New function, new scope
// "y" is created in scope, "x" is accessible through the scope chain
var y = "nice";
// Now VALID because FunctionDeclaration is top-level of Function
function myfunction() {
}
})(); // Invoke immediately
// No "y" here - not in scope anymore
Realize this is old, but figured I would update for ES2015.
The do have a bit more meaning with let + const as found here https://babeljs.io/docs/learn-es2015/
function f() {
{
let x;
{
// okay, block scoped name
const x = "sneaky";
// error, const
x = "foo";
}
// okay, declared with `let`
x = "bar";
// error, already declared in block
let x = "inner";
}
}
I don't understand the reasoning behind the outermost curly braces, but functions are always written inside curly braces in javascript.
If you are working with other developers they may find the outer curly braces more confusing than helpful and there could be some negative effects : https://web.archive.org/web/20160131174505/http://encosia.com/in-javascript-curly-brace-placement-matters-an-example/
There are probably many reasons NOT to write code this way... readability is #1, as most would find this makes the code harder to read. However, there is technically nothing wrong with coding like this, and if it's easier for you to read, then it should be fine.
I think there will be problems with this convention when you start coding more complex programs. There must be a good reason why people don't code like that other than adding extra lines of code.
But since Javascript doesn't have block scoping, the code will still work.
Related
Note: this isn't exactly a question about scope.
I'm reading a book that says that many people can add scripts to a web page, and for that reason, having global variables can cause naming collision. For example, say one person adds this script:
<script>
function showAreaOfWall(height, width) {
let area = height * width
return `<h1>Area: ${area}</h1>`
}
let message = showAreaOfWall(5, 20)
document.write(message)
</script>
The script above has a global variable called message, which can't be declared again anywhere else. However, say someone does exactly that. Someone adds in another script that declares a variable with the same name.
<script>
function welcomeMessage(user) {
return `<h1>Welcome, ${user}!</h1>`
}
let message = welcomeMessage('Luke')
document.write(message)
</script>
As expected, we get an error:
Uncaught SyntaxError: Identifier 'message' has already been declared
Now my question is, how does an Anonymous Function or IIFE prevent this from happening?
This is how I'm thinking about it. Let's see what happens if both persons used IIFEs in their scripts:
<script>
document.write(function(height, width) {
let area = height * width
return `<h1>Area: ${area}</h1>`
}(5, 20))
</script>
<script>
document.write(function(user) {
return `<h1>Welcome ${user}!</h1>`
}('Luke'))
</script>
That one works perfectly. Cool. No name collisions. But it defeats the whole purpose of functions, because these functions aren't even reusable anymore, I'm not storing them anywhere...
Ok, those were IIFEs. But also, I can't wrap my head around how Anonymous Functions would prevent naming collisions. Both scripts can still assign an unnamed function to a variable with the same name.
How am I looking at this wrong?
It doesn't matter if the function is anonymous or named. It doesn't matter if it is immediately invoked or not.
A function creates a new scope.
Your edit:
Note: this isn't exactly a question about scope.
It's entirely about scope. Using different scopes is how collisions are prevented.
A variable declared (with let, const or var) inside a function is a different variable to one declared in a different function or outside of any function, even if it has the same name.
That said, this was how we handled scoping of variables in ES5.
In modern JavaScript we use either blocks or modules.
Modules have similar scoping rules to functions, and blocks are the scoping level for let and const.
{
let foo = 1;
document.write(foo);
}
{
let foo = 3;
document.write(foo);
}
Just opened a client's javascript file and the first lines are along the lines of this:
{
var s_account="blog";
}
Which I don't get. Normally, in my experience, curly braces wrap around a function...
function welcome(){ ...
...or a json JavaScript object
var attributes = { this : "that...
Can anyone tell me why there are curly braces with no text before them or after them? What does it do / what is the point of it?
It's a block and completely pointless unless you label it:
block: {
var s_account="blog";
console.log("executed");
break block;
console.log("not executed");
}
The only logical reason to do something like this, in my mind, is as an organizational technique.
function banana(){
// private members
{
var foo = "foo",
bar = "bar",
baz = "baz";
function bux(){
console.log("bux");
}
}
// public members
this.fin = "fin";
this.fang = "fang";
this.foom = "foom";
this.shamalamadingdong = function(){
bux();
};
}
Also, most IDEs will allow you to collapse that "private members" block and get it out of your way.
That's a block statement. Block statements have multiple purposes, none of which are being used by that code (other than perhaps to group the content together as Shmiddty suggested). (In fact, I'd say in that code they're counter-productive, because for the many people coming to JavaScript from languages where all variable declarations are block-scoped, they create the impression that the variable is scoped to the block, which it isn't.)
Uses it can have:
Scoping let, const, and class
If that code were using let, const, or class, the block would scope the resulting identifier because let, const, and class are block-scoped in JavaScript. So this outputs "bar":
{
var foo = "bar";
}
console.log(foo);
but this throws a ReferenceError because foo is scoped to the block:
{
let foo = "bar";
}
console.log(foo);
Providing a block to break
As Esailija points out, if it were labelled and using break, the break would exit the block early.
Grouping statements attached to a flow-control statement
The most common use of a block statement is to group together the statements attached to a flow-control statement like if and for. In this fairly typical if:
if (something) {
doThis();
doThat();
}
...the {} aren't part of the if (you can write if without using {}), they're a block statement attached to the if.
Can anyone tell me why there are curly braces with no text before them or after them? What does it do / what is the point of it?
There is no significant point to them in Javascript. It will act exactly the same as if the code was just
var s_account="blog";
Speculation
In other languages which have block scope, this might restrict the scope of the variable, but since JS doesn't have that feature (for better or worse), braces without a control structure or function are essentially meaningless and ignored.
Most likely this code was left over from a deleted function or if statement however. It definitely is not a pattern to be copied.
It's called a block statement. It lets you group expressions. It's normally used with control structures like if and while, but can also be used on its own.
Since JavaScript doesn't have block scope, the code runs in the same scope (as if the {} weren't there).
Example:
{
var s_account="blog";
}
console.log(s_account);
That works fine.
Quick addition.
In some IDE like Visual Code, putting Curly Braces will actually create a visual block with a 'drop-down' arrow, allowing you to completely hide a portion of code with just a click.
It helps with code organization.
I'm using it when creating HTML element with a lot of CSS.
Since it does not affect code execution, this is very useful.
Lately after ES6 released, many sources suggested that I use "const" and "let" instead of "var", and that I should stop using "var" in my JavaScript.
What I wonder is, if "var" has no advantage over "let" in all points of view, then why didn't they just fix var, or even deprecate "var" instead of letting them go along side each other?
Backwards compatibility.
You're right in saying there is no real advantage to using var over let - if you define them at the start of a function their meaning is basically identical.
You're right that there is no real reason to write new code using var (except maybe this, if relevant).
There are pages on the internet that are decades old though, and no one is going to rewrite them. There is nothing really to gain by removing var from the language. For languages like HTML and Javascript that are interpreted - backward compatability is absolutely mandatory.
That is also why they chose not to simply redefine var. Take the following example code;
// THIS IS AN EXAMPLE OF BAD CODE. DO NOT COPY AND PASTE THIS.
if (logic) {
var output = "true"
} else {
var output = "false"
}
console.log(output)
If var was changed to behave like let then the console.log would cause a reference error because of the scope difference.
I believe sometimes you need to redeclare a variable to write less code.
One example is this function that generates a unique id:
function makeUniqueId(takenIds) {
do {
var id = Number.parseInt(Math.random() * 10);
} while (takenIds.includes(id))
}
Which may be invoked like that
makeUniqueId([1,2,3,4,5,6,7])
Here I declare id variable simply inside do block and it get's "hoisted" to the function scope. That would cause an error if I used let, because while block wouldn't see the variable from the do block. Of course I could declate let before do..while, but that would create the same function scoped variable with extra line of code.
Another example is when you copypaste code to devtools console and every time variables get redeclared.
One more example. What if you want to keep your variable declarations close to their usages but still treat them as function globals? If you use let in this fashion, you'll get rather confusing expirience in dev tools (all those Block, Block scopes).
But var 'keeps' them together in one 'Local' list:
Everything has their own advantages and disadvantages using var const and let is dependent on their use cases.
var
Variable declarations are processed before the execution of the code.
The scope of a JavaScript variable declared with var is its current execution context.
The scope of a JavaScript variable declared outside the function is global.
let
The let statement allows you to create a variable with the scope limited to the block on which it is used.
const
const statement values can be assigned once and they cannot be reassigned. The scope of const statement works similar to let statements.
I hope you understand.
I have heard that since JavaScript would hoist all the local variables to the front of the function, it is better if the programmer just hoist it himself or herself, so that everything is seen as how things would actually occur.
Example is:
var i, result = [];
which is to declare all local variables at the beginning of the function.
But I also saw in some classical code, such as in React JS's source code that it would do
for (var i = 0; i < ...; i++) { ... }
that is, declaring it when i is first used -- so that if this line is removed, the declaration will be removed together.
If we hoist it manually, there is a danger that when that loop is removed, the var i; is still left there. (although linting probably would catch it).
I also have seen weird look from interviewers when I hoists all the variables to the front of the function definition too.
Should we hoist all variables to the front? Or what if we hoist all variables except the temporary variables such as i and j?
Limiting the exposure of variables to the context they are useful in can be an extremely valuable auto-documentation strategy: It lets the next person who picks up the code know where variables are and are not relevant. So no, don't "hoist" because the JavaScript engine is internally doing it
I also have seen weird look from interviewers when I hoists all the variables to the front of the function definition too.
Should we hoist all variables to the front? Or what if we hoist all variables except the temporary variables such as i and j?
There are basically two schools of thought on this. One is to declare all of your variables in one place, usually at the top of whatever they are scoped to (which is the function in which they are defined, if you are using the var keyword). The other school of thought is to declare variables as closely as you can to where they are used. They both have valid arguments, and honestly is a matter of opinion and preference.
Before getting into let and ES6, I will first talk about the two arguments above.
Declaring at the top of the scope
The advantages of this are that you always know where your variable declarations are, and you are always aware of the parent scope. Immediately when looking at the function, you can determine what variables are used throughout, and you can trace where they are used from there.
The disadvantages of this are that, depending on your code structure, it may be 100 lines from where a variable is declared and where it is used, which can make debugging a bit of a challenge sometimes and requires you to carefully trace the variable you think you are using in the function, because it may not always be the one declared at the top, especially in the case of shadowing.
Declaring as close in proximity to where the variables are used
The advantages of this are that when trying to determine variable scoping and shadowing, it is very easy to determine what version of the variable you are working with (especially with nested functions). The other advantage is code-cleanup. If you remove a function or a loop and there is a variable declaration right above it, it is usually a pretty good reminder to remove that variable declaration as well because it will not be needed anymore. Obviously that's not always the case, but many times it is. When declaring at the top, variables can get lost in a sea of declarations and be left unused - yeah a linter can catch that, so it may be a moot point, but it's a point nonetheless.
The disadvantages of this are the exact opposite of the advantages of declaring at the top. If you are looking to see what variable names / identifiers are used in a given scope, you kind of have to go digging. CTRL + F is your friend, but it is faster to look at a list that is all in one place.
Now what about let??
Again, there are two schools of thought on this: one is "let is the new var" and the other is that "let simply allows us to do syntactically what we already were doing stylistically"
For example, take this code:
var result;
for (var i = 1; i <= 10; i++) {
result = 2 * i;
console.log(result);
}
Vs.
for (var i = 1; i <= 10; i++) {
var result = 2 * i;
console.log(result);
}
Now, from the compiler's perspective, they are identical. However, the second version (stylistically) is telling the reader of the code "The result variable is only being used inside this for loop", whereas the first version is ambiguous to the reader as to what may or may not be happening to the result variable later on in the code. These are stylistic and conventions that developers unspokenly adhere to in order to convey intent of the code. And that is the argument of the second school of thought - let simply allows us to do, syntactically, what we are already doing stylistically.
This might have been relevant a few years back.
Now, you should use ES5 or later, which introduced the let keyword, which solves the hoisting issue. let declared variables are block-scoped and will not be hoisted.
I guess sometimes it makes sense to use strict mode
"use strict";
which can be implemented for the whole file or for a function
function strictFunction() {
"use strict";
var y = 3.14; // This is ok
x = 2.414; // This will cause error
}
which can help writing more secure code by avoiding global variables. So technically it depends how your for loop is being use. Reference "use strict";
You can also use let instead or var as suggested by #RemcoGerlich to scope your variables
Is defining JavaScript variables inside if-statements correct?
if(a==1){
var b = 1;
} else {
var b = 0;
}
I know the code above will work, however, WebMatrix highlights the variables.
Should I define the variables outside the if-statement? Or the first option's correct? Or it doesn't really matter?
var b = '';
if(a==1){
b = 1;
} else {
b = 0;
}
As of the official release of ES2017 spec (2017-07-08), EcmaScript does support true block scope now using the let or const keywords.
Since ECMAscript doesn't have block scope but function scope, its a very good idea to declare any variable on the top of your function contexts.
Even though you can make variable and function declarations at any point within a function context, it's very confusing and brings some weird headaches if you aren't fully aware of the consequences.
Headache example:
var foo = 10;
function myfunc() {
if (foo > 0) {
var foo = 0;
alert('foo was greater than 0');
} else {
alert('wut?');
}
}
Guess what, we're getting a 'wut?' alert when calling myfunc here. That is because an ECMAscript interpreter will hoist any var statement and function declaration to the top of the context automatically. Basically, foo gets initialized to undefined before the first if statement.
Further reading: JavaScript Scoping and Hoisting
Note that ECMAscript 6 does support block-level variables using the 'let' rather than the 'var' keyword. While variables declared with 'var' are hoisted to be function-scope regardless of where they are declared, those defined using 'let' are scoped to the enclosing block only.
Putting a var inside an if statement is not against "the rules" of the language, but it means that, because of var hoisting, that var will be defined regardless of whether the if statement's condition is satisfied.
Because JavaScript's variables have function-level scope, your first example is effectively redeclaring your variable, which may explain why it is getting highlighted.
On old versions of Firefox, its strict JavaScript mode used to warn about this redeclaration, however one of its developers complained that it cramped his style so the warning was turned off. (Current versions of Firefox support a block-level variable declaration syntax.)
See function four on What is the scope of variables in JavaScript?
As of 2012, there's no block-level scope in JavaScript. So your first version is fine: the variables are defined in the scope outside the if block.