for(var i = 0; i < 100; i++){
var foo = 5;
}
It works ...but is this bad?
I know I can declare var foo outside, but why do that when I'm only going to use it in the loop?
Over time my personal style has grown into a preference for declaring variables where they "actually are" in the "mind" of the particular language I am working in. For JavaScript this means putting variable and function declarations in the positions where the language would hoist them anyway.
This is for clarity, precise communication, understanding, maintainability, to keep my own mental processes parallel with the processes of the language, just to mention a few good reasons.
So in this particular case, I would not put a var foo = 5; declaration into the body of a for loop, for the simple reason that it is not doing what it looks like it is doing, i.e., it is not in fact redeclaring/re-scoping the variable with every iteration. (Placing the var declaration in the initialization portion of the for loop's header (initialization; condition; afterthought) would be more reasonable, and certainly the correct place to put it in languages that do have block-level variables, such as when JavaScript finishes adopting the let-style declaration for block-level scope.)
Notes:
This practice may not seem "normal." My mind prefers to keep variables "close" to their use, and my current practice does not come naturally to the way my mind works. But as a programmer through the years, experiences with confusion, bad communication, misunderstanding, unmaintainable code impossible to unravel, etc., have more than justified the extra discipline that it takes me to follow this style of declaring variables in the locations corresponding to their actual scope, regardless of the language.
One extra benefit of this practice for me has been that it encourages me to keep my functions modular and reasonable in size.
Along the same lines, following this practice automatically helps keep my code organized in a sensible way. For instance, if putting my functions first causes there to be excessive functions before the code I am actually working on, and I therefore get irritated about having to go down two pages to edit my program, following this style automatically gives me incentive to organize my code into an appropriate structure of distinct files.
P.S. One could bring up a point that some functions are so long that this practice makes variable declarations end up pages away from where they are used. Yes, I have seen code where that is true, and perhaps even code where that cannot be helped. Yet I can't help observing the parallel that is equally true for authors of prose as it is for computer programmers. As skill level grows, the lengths of authors' sentences (and sizes of programmers' functions) tend to grow, and then as the skill level continues to grow yet higher, the lengths of sentences (and sizes of programmer's functions) tend to shorten once more.
It is bad because it gives the false impression that i and foo are local variables.
for(var i = 0; i < 100; i++){
var foo = 5;
}
foo; // 5
This might not be a problem with simple code, but if you use closures it becomes apparent that there is only one foo:
var counters = [];
for (var i = 0; i < 100; i++) {
var foo = 5;
counters.push(function() { foo++; return foo; });
}
counters[0](); // 6
counters[0](); // 7
counters[1](); // 8 (!)
To create foo in a different scope a function needs to be introduced:
var counters = [];
for (var i = 0; i < 100; i++) {
(function() {
var foo = 5;
counters.push(function() { foo++; return foo; });
})();
}
counters[0](); // 6
counters[0](); // 7
counters[1](); // 6
Here is a real-life example of things going wrong due to this: setTimeout in for-loop does not print consecutive values
Since JavaScript 1.7 you can use the let keyword (see MDN) to create true local variables.
Related
I was looking for some micro optimizations of some JavaScript legacy code I was revisiting and noticed that in most frequently called for loops, counters were declared once in the global scope, outside the functions using them. I was curious whether that was indeed an optimization therefore I have created the following test case in JavaScript:
var tmp = 0;
function test(){
let j = 0;
function letItBe(){
for(j = 0; j < 1000; j++){
tmp = Math.pow(j, 2);
}
}
function letItNotBe(){
for(let l = 0; l < 1000; l++){
tmp = Math.pow(l, 2);
}
}
console.time("let it be");
for(var i =0; i < 10000; i++){
letItBe();
}
console.timeEnd("let it be");
console.time("let it not be");
for(var i =0; i < 10000; i++){
letItNotBe();
}
console.timeEnd("let it not be");
}
test();
What happens is that letItNotBe() runs significantly faster than letItBe(), in Chrome, Firefox and also NodeJS
Chrome:
NodeJS:
Changing let with var makes no difference.
Initally my logic was that declaring a new counter variable every time a function is called would be indeed slower than if a variable is initially declared and then simply reset to 0. However, it turns out to be quite the oposite and the difference in execution time is quite substential.
My simple explanation is that when the counter variable is declared ouside the function using it, in some way the JS transpiler needs to refer to this variable. And since it is in the parent scope it takes more executions to reference it when incrementing. However that's just blind guessing.
Can anybody give any meaningful explanation why this is happening, since I need to refactor the code and give a meaningful explanation mysefl besides the test that I already have :) Thanks.
I've read a book High Performance JavaScript, the author explained this at Chapter 2 "Data Access" - Section "Managing Scope" - Part "Identifier Resolution Performance".
Identifier resolution isn’t free, as in fact no computer operation
really is without some sort of performance overhead. The deeper into
the execution context’s scope chain an identifier exists, the slower
it is to access for both reads and writes. Consequently, local
variables are always the fastest to access inside of a function,
whereas global variables will generally be the slowest (optimizing
JavaScript engines are capable of tuning this in certain situations).
...
The general trend across all browsers is that the deeper into the
scope chain an identifier exists, the slower it will be read from or
written to.
...
Given this information, it’s advisable to use local variables whenever
possible to improve performance in browsers without optimizing
JavaScript engines. A good rule of thumb is to always store
out-of-scope values in local variables if they are used more than once
within a function.
In your case, letItBe and letItNotBe work in the same way, using the same out-of-scope tmp variable, and both of them are closures.The only difference is the counter variables of for loops:
variable j is defined for function test(), it's 'out-of-scope' for function letItBe(), so executing letItBe() will cause the engine to do more works on identifier resolution
variable l is defined in scope of for loop (see let keyword in the for loop), so resolution is faster
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
I want to know the overhead of JavaScript closures. Suppose I have the following function:
function sum(arr, sumMethod) {
var totalSize = 0;
for (index = 0; index < arr.length; ++index) {
totalSize += sumMethod(arr[index]);
}
return totalSize;
}
If I want to know the total size of all my transfers, then I could use a global accessor function to obtain the size of a transfer. This function is passed to sum:
// Use a "global" method that is initialize only once
function getTransferSize(transfer) { return transfer.size };
...
// Obtain the total size of all transfers (called pretty often)
var totalTransferSize = sum(transfers, getTransferSize);
Another approach is to inline the accessor like this:
// Obtain the total size of all transfers (called pretty often)
var totalTransferSize = sum(transfers, function (transfer) { return transfer.size });
I would think the closure is only "compiled" once and reused over and over again, so the actual execution performance would be equal. A collegue of mine thinks that the closure is created over and over again and it hurts performance.
Can anyone explain what is the preferred method?
REMARK: I am actually using CoffeeScript, which makes closures much more readable. In CoffeeScript the code would look like this:
totalTransferSize = sum transfers, (t) -> t.size
I find this much more readable then using a global accessor function, so I would prefer to inline the accessor.
A collegue of mine thinks that the closure is created over and over again
Yes. Every time the function expression is evaluated, a new function object is instantiated.
and it hurts performance.
Unlikely. If you'd really care, measure it. The instantiation is probably much cheaper than the loop with the calls.
I would think the closure is only "compiled" once and reused over and over again
Yes, the code is compiled only once and shared by all the function instances.
so the actual execution performance would be equal.
Of the single call, yes.
Can anyone tell me why use one var declaration for multiple variables and declare each variable on a newline consider is a good programming behavior?
// bad
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';
// good
var items = getItems(),
goSportsTeam = true,
dragonball = 'z';
It is not considered 'good' or 'bad'. It's a matter of preference.
The guy who built the code quality tool JSLint, Douglas Crockford likes it.
One 'advantage' it might have is that it avoids the possibility of variable hoisting. In JavaScript all var declarations move to the top of their scope automatically.
Here is why Crockford thinks the second option is better:
In languages with block scope, it is usually recommended that variables be declared at the site of first use. But because JavaScript does not have block scope, it is wiser to declare all of a function's variables at the top of the function. It is recommended that a single var statement be used per function. This can be declined with the vars option.
It's a preference, I wouldn't say good or bad. Yes JSLint complains about it, I don't really like how it complains about for loop variables being inline as well. The reason that it was put in JSLint was to prevent possible hoisting confusions.
Also in some cases declaring all of your variables at the top will lead to a slightly smaller file. Consider the following:
var a = 10;
a++;
var b = 20;
After Google Closure being run over it
var a=10;a++;var b=20;
As opposed to this if we pull b's declaration to the top.
var a=10,b;a++;b=20;
The main benefit (aside from style preference, I guess) is that it will prevent you from writing code that suffers from unintended variable hoisting consequences.
Take this example:
var foo = function(){alert('foo');}
function bar(){
foo();
var foo = function(){alert('foobar')};
foo();
}
bar();
By reading this code, the intent of bar appears to be as follows:
Call the outer foo function to alert the string 'foo'.
Create a local variable, foo.
Call the local foo function to alert the string 'foobar'.
In reality, what happens is this:
The local variable foo is hoisted to the top of the bar function.
foo now actually refers to the local variable instead of the outer variable of the same name. But since the local hasn't been assigned yet, its value is undefined. Hence, when you try to invoke foo, you'll get a TypeError.
Nothing. Because you threw an error. That's it. Your code broke.
The arguments for Crockfords preference have been well made and are valid. I am just beginning to return to the first format now however, as I believe that for experienced developers who understand variable hoisting and are not likely to fall foul to it, there are 2 advantages that I can think of:
When new variables are added to the list of definitions, diffing is made easier. This means you are likely to experience fewer merge conflicts (simple though they may be to resolve) and less cognitive load when analysing diffs. For similar reasons I have also been converted to dangling commas, which I would never have expected xD
As #ldsenow identified, it can make searching for variable definitions more simple. You will always be able to search for var <name> and get the result you want and nothing else.
I see two differents way for declaring variables when making a "for loop" in javascript:
First way:
for (var i = 0, l = [].length; i < l; i += 1) {
// make something
}
Second way:
var i;
var l;
for (i = 0, l = [].length; i < l; i += 1) {
// make something
}
Is there some reason to prefer one of these?
They are same, you can use either BUT first is more readable and terse.
The point is that variables in both cases are local with the presence of var keyword. With first method also, you create two local variables:
var i, l
Instead of
var i
var l
Why use var keyword again and again when only one can do it. In fact that turns out to be one of the good practices of JS.
Given the code you show, they are the same thing. However, JS has some oddities which could cause issues in more complex code. Also, there is a question of maintainability and readability for future devs. Some of it is very subjective, some of it is objective.
I use a combination of the two, with slight variation--single var statement, top of scope.
var x = function () {
var i,
l;
for (i = 0, l = [].length; i < l; i += 1) {
// make something
}
};
The reason being that I prefer a single var statement per scope (function), and that statement to be at the top of the scope. JSLint/JSHint enforce this by default. Objectively, it helps avoid issues with the JS hoisting mechanism, which moves all variable declarations to the top of scope during the pre-execution pass. Admittedly subjectively, it makes very clear to later developers which variables are introduced in this scope. Any other var in use in the scope is assumed to be coming from a higher-level scope.
In javascript there is no difference except from a maintainability point of view. keeping declarations and usage close by helps in better readability. You should choose which ever is more readable.
No, both those are correct. I prefer the first myself.
An incorrect way is:
for (var i = l = 0; ...; ...) {
...
}
Where there is no comma between i and l wich causes l to be global.
No, at least in Chrome the scope is exactly the same and both ways are equivalent.
actually according to the almighty crockford there is: because javascript has function scope it is preferred to always declare variables first thing in the head of the function.
However, as others have pointed out, it doesnt really matter and should be done according to personal taste and readability.
The reason why one would prefer the second over the first is that variables in JS don't have block scope, but instead lexical (or function) scope, which means that variable are visible within the function they are defined (they are also visible in nested functions).
Example:
function foo() {
for (var i = 0; i < 10; i++) {
alert(i);
}
alert(i); // works, because i has lexical scope
}
In most C-like languages, variables have block scope, which means they are visible within the block where they are defined, so:
void foo() {
for (int i = 0; i < 10; i++) {
print(i);
}
}
print(i); // won't work, i is not visible any more
So, people coming from languages like Java/C/C++ may think that var i in the first example has block scope, where it actually has not. This is why some programmers prefer declaring all variables at the beginning of functions.
Personally I think even then you should stick to the habit to declare variables as close as possible to where they are used.
EDIT
As JAAulde mentioned, you should only declare variables close to their usage if you've really understood JS scoping rules (and quirks).