In Javascript, you can have lonely code blocks, that is, code blocks without an if, function or something like that preceding them, placed arbitrarily in the code, like this:
var a = 3,
b = 4;
{
a = 50;
b = 50;
}
alert(a + b); //alerts 100
I know some other languages have this (I think C++ does), and they use it for scope control: variables declared inside the lonely code block cannot be accessed outside of it. But since Javascript has function scope rather than block scope, you have to use a self-executing function (function(){})() to acheive the same effect.
Is there a purpose for this construct? Have you ever seen anybody use it? Does the spec mention it? Is this just a side effect of the grammar having some sort of general rule about code blocks?
As I found out after googling my answer for How are labels used with statements that are not a loop?, the lonely code blocks can be related to labels:
myLabel:
{
for(x in y) {
break myLabel;
}
}
Will break out not only of the loop, but of the outer code block as well.
Update (as this question shows up high on Google for "javascript code block"):
With the introduciton of the let keyword in ECMAScript 6, code blocks can also be used to limit scope of variables.
{
let x = 20;
alert(x) // 20
}
alert(x) // undefined
Only code readability, nothing more.
They do not even give you the advantage of closures:
var c = 'fail';
{
var c = 123;
}
alert(c); //alerts 123
(see it live)
Only readability. Other than that, nothing. Do not do this as it's not future-proof. The following will happily break:
"use strict";
var a = 3,
b = 4;
{
a = 50;
b = 50;
}
alert(a + b); //alerts 100
I used to use it myself as it allowed logical separation of functionality, but no longer do due to the above.
Related
I want to know what the best practices are before I go to my colleagues for a code review.
I know that the following code works. My question is whether relying on closure this way is generally accepted in JavaScript or if there's something problematic here that I'm missing? Thanks
EDIT: updated the snippet to more clearly show what I'm trying to achieve (cleaner, more readable code)
// All this is happening inside a function. Declared vars are not global.
var x, y, z; // lots of variables to declare (to use in closures)
setupVars(true); // lots of variables to setup
useVars(); // lots of variables to use
function setupVars(condition) {
if(condition){
x = 1;
y = 2;
z = 3;
} else {
x = 4;
y = 5;
z = 6;
}
};
function useVars(){
console.log(x);
console.log(y);
console.log(z);
}
Using variables with same names as the global ones, inside a function, is not a good coding practice. In the above code, you should consider renaming x inside the function.
Otherwise, if the function is as simple as the one shown above, you could just do something like this
function modify(value){
return modified_value;
}
Learning JS here, I run JSLint on this code:
/*jslint devel: true*/
function Animal(n) {
"use strict";
this.name = n;
this.prop = "a";
}
var a = new Animal("duppa");
for (v in a) {
if (a.hasOwnProperty(v)) {
console.log("property:" + v);
}
}
I get:
jslint:test2.js:11:6:'v' was used before it was defined.
jslint:test2.js:11:8:Cannot read property "kind" from undefined
jslint: ignored 0 errors.
It obviously complains that I did not declare v up front:
/*jslint devel: true*/
function Animal(n) {
"use strict";
this.name = n;
this.prop = "a";
}
var a = new Animal("duppa");
var v;
for (v in a) {
if (a.hasOwnProperty(v)) {
console.log("property:" + v);
}
}
This shuts JSLint up, but is it really necessary? In general I try to follow good conventions but is this one really necessary in JS? E.g. Python lives happily without such stuff (for x in range(10)... etc).
Yes, you absolutely should declare the variable. Otherwise you're declaring v at global scope which is never good, but it's particularly bad for counting variables which are a single letter long like v.
Consider the case where two people get lazy about declaring a variable of the same name:
// Your code, which iterates over a nested array
var arr = [ [1, 2], [3, 4] ];
for (i = 0; i < arr.length; ++i) {
AwesomeLibrary.doSomething(arr[i]);
}
// way down elsewhere, in awesome_library.js...
function doSomething(arr) {
for (i = 0; i < arr.length; ++i) {
// Now your `i` is clobbered, and we have a subtle but devastating bug
}
}
This doesn't even require two lazy people: If you work with JavaScript long enough and refuse to declare your variables, you will eventually do this to yourself.
There are 10 types of people in the world. Those who understand why you declare variables in javascript and those who have regular sex. (Just smile)
You must understand that every function have their own scope and you must use this scope. If you don't use declaration inside your function you change the global state, and it affects of course on many things.
So use var and don't create global variables !!!
It is always a better practice to define your variables before using them. Here javascript's for loop requires you to define i, because it is in the for loop, use
var v;
for( v in a)
As far as my understanding goes, if you use a variable without declaring it within a function scope, it gets declared in the global scope, which isnt a best practice. You will soon cloud your global scope with variables.
//This creates a global variable
function not_a_best_practice(){
a=10;
}
//This creates a local variable
function not_bad(){
var a=20;
}
This answer may throw more light on the discussion at hand:
What is the scope of variables in JavaScript?
Remember that JSLint doesn't complain because of some obscure academic reason but because it protects you from major problems your application may potentially suffer from.
You declare a variable to contain the variable in the current scope. It's a safeguard for you and your program as well making it more readable code (global vars appearing out of nowhere are always confusing).
Imagine if you had a global variable v in your application and then used the same nomenclature (v) for iteration in a function. Javascript will automatically assume that the global variable is being used and you'll find yourself with unwanted values in your global. Having said that, the less stuff you put in the global namespace the better.
Option1 : multiple var without assignment
function MyFunction() {
var a = null;
var b = null;
....
var z = null;
a = SomeValue;
b = SomeValue2;
....
}
Option 2: one var statement, no assignment
function MyFunction() {
var a, b ..., z;
a = SomeValue;
b = SomeValue2;
....
}
Option 3: multiple var statements with assignment
function MyFunction() {
var a = SomeValue;
var b = SomeValue2;
....
var z = SomeValue26;
}
Is there any performance benefit of using a particular option? Is it true for both primitive type assignments AND object reference assignments?
Thanks for your input.
"premature optimization is the root of
all evil"
I don't think there will be any significant performance change with any of this options.
(IMO) The third option is the most readable option and closest to dynamic memory allocation like C# etc'. But this is my humble opinion, Choose what you like the most.
If it really bothers you and you can't sleep without an answer, test it with jsPerf.
#Chad made a jsPerf so you can sleep well tonight...
To understand the performance you should first understand hoisting. Let's take the following code:
var x = 1;
function bar(val) {
var returnVal = val * 2;
return returnVal;
}
function foo(val) {
var returnVal = 10;
returnVal *= bar(val);
return returnVal;
}
var y = foo(x);
console.log(y); // 20
Hoisting basically means that the JavaScript interpreter will 'hoist' the variable declaration to the top of its scope. Making this example look more like this:
var x, y;
x = 1;
function bar(val) {
var returnVal;
returnVal = val * 2;
return returnVal;
}
function foo(val) {
var returnVal;
returnVal = 10;
returnVal *= bar(val);
return returnVal;
}
y = foo(x);
console.log(y); // 20
So, in your examples given, Option 2 and 3 will basically do the same thing. Since the interpreter will move those declarations to the top. At that point it's a decision of preference. A lot of people avoid doing something like var x, y, z; saying it's dangerous. I, personally, do it. In whatever scope I'm in I will declare all variables at the top, and then use them below. But either way works.
Now, your first example is the least efficient. After hoisting it will look like this:
function MyFunction() {
var a, b, ... z;
a = null;
b = null;
...
z = null;
a = someValue;
b = someValue2;
...
z = someValueN;
}
It basically results in setting the variables twice.
In Chrome, execution times are identical.
The only real consideration here is optimizing network transfer.
Consider var a=1;var b=2;...;var z=9; versus var a=1,b=2,...,z=9;
If you put a ;varĀ in front of each identifier, that's 5 bytes (assuming a single-byte character encoding), versus 1 byte for a ,. Thus, declaring 26 variables, you can save 100 bytes by writing varĀ once and listing identifiers with commas.
Granted it's not a huge savings, but every byte helps when it comes to pushing bits over the network. It's not something to worry a great deal about, but if you find yourself declaring several variables in the same area, using the variable declaration list is an easy way to shave a few bytes off your JS file.
That seems like premature optimization, the root of all evil.
How many times will it be executed? What fraction of of the whole program will this consume?
I will counter your question about performance with a few questions:
Have you noticed an issue with performance?
Have you determined that your var statement was the bottleneck?
Have you tested each version?
I'm going to assume the answer to all of these was no.
None of the options should make any significant difference, although the only way to know for certain is to run them and test. JavaScript being an asynchronous client-side language means that you'd have to run a seriously enormous amount of code to have the var statements be a bottleneck of any sort.
In the end, if you're deciding which version to use, I would recommend using a single var statement without assignment:
function () {
var a,
b,
c,
foo,
bar,
fizz,
buzz;
a = 1;
...
b = 3;
}
The reason for this is that this is essentially how the code will be executed due to variable hoisting. I can then move the initialize statement so where the variable is first used, such as in a for loop:
function foo(arr) {
var i,
l;
...
for (i = 0, l = arr.length; i < l; i++) {
doStuff(arr[i]);
}
...
}
They all basically do the same thing: declare a variable and eventually define it (assign something to it). The only thing you're changing throughout your examples is the order in which that occurs, and even that depends on the browser that is compiling your JavaScript -- some might perform optimizations that others do not.
There are some stylistic guidelines you should follow though, and this answer explains them well. Keep in mind that that answer is technology agnostic and may not apply to JavaScript at all.
Just stay away from option 1 if possible, there is no need to make two assignments.
Even variables declared inside a for loop or other compound statement/block will be available outside its containing block.
You can also do:
function MyFunction() {
var a = SomeValue, b = SomeVavlue2;
}
In Javascript, you can have lonely code blocks, that is, code blocks without an if, function or something like that preceding them, placed arbitrarily in the code, like this:
var a = 3,
b = 4;
{
a = 50;
b = 50;
}
alert(a + b); //alerts 100
I know some other languages have this (I think C++ does), and they use it for scope control: variables declared inside the lonely code block cannot be accessed outside of it. But since Javascript has function scope rather than block scope, you have to use a self-executing function (function(){})() to acheive the same effect.
Is there a purpose for this construct? Have you ever seen anybody use it? Does the spec mention it? Is this just a side effect of the grammar having some sort of general rule about code blocks?
As I found out after googling my answer for How are labels used with statements that are not a loop?, the lonely code blocks can be related to labels:
myLabel:
{
for(x in y) {
break myLabel;
}
}
Will break out not only of the loop, but of the outer code block as well.
Update (as this question shows up high on Google for "javascript code block"):
With the introduciton of the let keyword in ECMAScript 6, code blocks can also be used to limit scope of variables.
{
let x = 20;
alert(x) // 20
}
alert(x) // undefined
Only code readability, nothing more.
They do not even give you the advantage of closures:
var c = 'fail';
{
var c = 123;
}
alert(c); //alerts 123
(see it live)
Only readability. Other than that, nothing. Do not do this as it's not future-proof. The following will happily break:
"use strict";
var a = 3,
b = 4;
{
a = 50;
b = 50;
}
alert(a + b); //alerts 100
I used to use it myself as it allowed logical separation of functionality, but no longer do due to the above.
I have a minor problem with a JavaScript snippet that I hope you can help me solving it.
var z=0;
function xyz() {
if (!z) {
z+=5;
var h=15; // The problem resides here
}
else {
var f=h+7;
alert(f);
}
z++;
return z;
}
When I registered this function to a click event handler on a button element, I was expecting to see by the second iteration of function execution an alert message displaying
22
What I had was a NaN message indicating that the variable h wasn't defined despite the explicit declaration statement within the if branch but when I omitted the var keyword, suddenly the function behaved :)
It's really puzzling for me as I am pretty sure that JS doesn't natively support block scoping except when using the let keyword introduced by Mozilla browsers. I am also darn sure that declaring variables using the var keyword creates local scope for them and therefore they become exclusively accessible within the function in which they are defined.
So, why on the world I have to declare h as a global variable for the function to work?
Any help would be very appreciated as I am new to Web Design and I am coming from graphic design background.
Note: Actually,this was not the real life problem that I faced during coding. I was trying to create a ticker that updates every 10 seconds automatically using the setInterval() method and then suppressing it when the user browses the headlines manually and when he's done, the script takes over once again.
I thought that a more generic and simple example is more suitable to explain the solution without getting into the details of the methods/properties used.
=======
UPDATE
I think I got it now. Functions don't have memories and thus can't remember values generated from previous calls. What I was doing actually is storing the value generated from the first call in a global variable that can be accessed in future calls. But I'm wondering is there any elegant way to achieve the same result other than using global variables?
No. In fact all your local variables are initialized at the beginning of your function. Your example code will be executed like this:
function xyz() {
var h;
var f;
if (!z) {
z+=5;
h=15;
}
else {
f=h+7;
alert(f);
}
z++;
return z;
}
You get NaN because in f=h+7 h is declared but it's value is undefined.
There is a more elegant way: using objects. There are may ways you can create objects, I use the most compact method here:
function MyObject() {
this.z = 0;
// it's safer to initialize all your variables (even if you dn't use the initial value)
this.h = 0;
this.f = 0;
this.xyz = function () {
if (!this.z) {
this.z += 5;
this.h = 15;
} else {
this.f = this.h + 7;
alert(this.f);
}
this.z++;
return this.z;
}
}
var o = new MyObject();
o.xyz();
o.xyz();
There are many-many docs about OOP in JS if you are interested.
Nope, only functions have a local scope. Do not put anything in global scope unless you absolutely have to.
You can use closures to get the result (I think) you want, e.g.
var xyz = (function() {
var z = 0;
var h;
return function() {
var f;
if (!z) {
z += 5;
h = 15;
} else {
f = h + 7;
alert(f);
}
return ++z;
}
})();
the first time nothing is shown, after that 22 is always shown and z increments 6, 7, 8, and so on.
--
Rob