Scope within for loop - javascript

I've been starting to use IIFEs within for-loops, like so:
var currentItem = 2; // IIFE helps prevent variable collision
for(var i = 0; myArray.length < i; i++){
(function(){
var currentItem = myArray[i];
// do stuff
})();
}
The main reason I've been doing this is to give some scope to the for-loop, so the variables don't escape this scope. Are there any negative effects/performance hits of doing so? And if so, what is the extent of their harm? Thanks!

Yes there is a performance cost in wrapping the body of a for statement into an anonymous function. The problem is the cost of creating a new function object for each iteration. That is, for each iteration a new function object is created with its own scope.
Performance comparison named vs anonymous function
This is a small comparison between named function and function declaration which may help you to understand the impact over the performance of your code. Note, in your case, the problem is not the anonymous function, but rather the cost of creating the function object.
ES6
I understand, you are trying to scope your variable to the for. I would suggest another solution to achieve this. If you can, try to use let keyword from ES6.
The let keyword has been introduced to overcome all of var's defects, such as this one. let allows you to declares variable that are limited in scope to the for block.
From the documentation:
let allows you to declare variables that are limited in scope to the
block, statement, or expression on which it is used. This is unlike
the var keyword, which defines a variable globally, or locally to an
entire function regardless of block scope.

Related

How variable can be accessible outside the for loop

In the code below, I have declared variable i on for loop , and trying to access variable i and I can get the last updated value of i, how.
for(var i = 0; i <= 10; i++){
console.log(i);
}
console.log(i,'outside');
The var statement declares a variable in the scope of the current function, not the current block (which is what the let statement is for).
After the for loop, you are still in the same function, so the variable still exists (with whatever value it was last set to).
(NB: For the purposes of var, the code which runs outside of any function is effectively treated as being in a function of its own).
Well, you are using var, and that's exactly a var type should do!
We have var and let, let's see how they work.
when you declare your variable like this :
let something;
You only access something in that very scope (for example your own for loop), and outside the scope, you cannot have it. On the other hand, when you are using var type, like this :
var something;
You are able to use this variable outside the scope ( again like your own for loop )
Notice that we are not talking about global variables. we are just talking about scopes.
If you rather declare a global variable, just use var in the global scope.

Access variable in if block

var func = function () {
var i: number = 0;
if (i == 0) {
var y: number = 1;
}
document.body.innerHTML = y.toString(); // js/ts should complain me in this line
};
func(); // output: 1
As you can see, I've declared variable y inside if block. So, I think it couldn't be referenced outside the scope.
But, when I've tried to run the code, the output is 1.
Is it an issue in typescript/javascript?
Variables in Javascript are hoisted, meaning that var y is moved to the top of the function as if it were declared there.
Initialization, however is not hoisted, so if you change i to be something other than 0, the variable y will still exist, but it will have the value undefined.
This means that the function is exactly equivalent to:
var func = function () {
var i: number = 0;
var y: number;
if (i == 0) {
y = 1;
}
document.body.innerHTML = y.toString(); // js/ts should complain me in this line
};
To get the behavior you expect, you need to use let, which is a part of ECMAScript 2015 (ES6). It is block scoped, as you expect. It will also effectively work so that it is accessible only from the point of definition onwards, which is also probably as you would expect.
If you re-declare a JavaScript variable, it will not lose its value.
The second reference might pave way for a new variable syntax. Actually if you recall variable declaration is not neccessary in javascript. Simpe
y=1;
also works.
The second time when you reference y, outside if block, in my opinion, it tries a re-declaration and retains the old value.
Reference - http://www.w3schools.com/js/js_variables.asp
& http://www.w3schools.com/js/js_scope.asp
Javascript has function scope afaik. Any variable declared within a function, should be accessible from anywhere within the function. So, if you have a function checking if i==0, then you can achieve what you are trying to achieve.
This is as it is supposed to be. Javascript scopes by function, not by block. (This does make it unlike many popular languages)
Variables declared like var myVar = 10; will seep into nested functions but not the other way around. Variables declared like myVar = 10; will go global.
I couldn't find anything which suggested that typescript was any different.
Variables declared inside of an if statement are not scoped to the if statement. They're scoped to the current execution context. There's the Global execution context and then when a function is run, it creates it's own execution context. Inside of your function, you created the variables y and i. It doesn't matter that y was created inside of the if statement, because once it runs, y is created in the scope of the function. So then you do y.toString(), which can access y because it's scoped to the function not the if statement. That's why you get the output of 1. This is not an error, it's by design.

JavaScript loop variable scope

Just a quick question about the scoping of JavaScript variables.
Why does the alert() function print the value of i instead of returning undefined?
$(document).ready(function () {
for(var i = 0; i < 10; i += 1){
}
alert("What is 'i'? " + i);
});
I'm fairly new to JS, and in nearly all other languages I've dabbled, a declaration in the scope of the for loop would contain the value to that said loop, but not in this case, why?
i.e. What is 'i'? 10' is printed.
See the MDN for the "initialization parameters" of a for-loop:
An expression (including assignment expressions) or variable declaration. Typically used to initialize a counter variable. This expression may optionally declare new variables with the var keyword. These variables are not local to the loop, i.e. they are in the same scope the for loop is in. The result of this expression is discarded.
JavaScript didn't have block scope until const and let were introduced, just var which is function scoped. Since the initialization of i is within one function, that variable is accessible anywhere else in that same function.
From MDN:
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.
The javascript folks are trying to fix this!
EcmaScript6 (aka EcmaScript 2015) is the latest version of javascript that was passed last summer and browsers are just starting to support its features.
One of those features is block-scope local variables with the "let" expression. As of right now (April 2016), most of the current versions of the major browsers support this except Safari. Few mobile browsers support this.
You can read more about it here (in particular, see the section "let-scoped variables in for loops"):
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
You can check current browser support here (look for the row Bindings -> let):
https://kangax.github.io/compat-table/es6/
Unlike other languages (for example: Java, C++, C), JavaScript doesn't support block scope. Once you declare a variable in a loop or in a function it's scope is within the function body if you do
for(i=0; i<arr.length; i++) {
var j=0;
// ...
}
here your i becomes a global variable and j become local to the function or script in which the loop is.
for(i=0; i<arr.length; i++) {
var j=0;
// ...
}
it is not correct to state that the above creates a global variable i. I believe you should always use var to declare variables (unless you are intentionally wanting a 'property' rather than a 'variable' -which is pretty unlikely in 99.99% of JS coding scenarios ...)
Omitting var when assigning an initial value to i isn't creating a local or even a global variable, it is creating a property i for the global object (which may seem/behave mostly like a global variable - but they have some subtle differences).
better would be:
var i;
for(i=0; i<arr.length; i++) {
var j=0;
// ...
}
now the loop is using a global variable i (or function local variable i, if this code appears in a function)
see more about this at what is function of the var keyword and variables vs. properties in Javascript
--
note, what is a little confusing is that you can re-declare a variable, for example in a second loop
for(var i=0; i<9; i++){
document.write('i = ' + i + '<br>');
}
for(var i=0; i<9; i++){
document.write('i = ' + i + '<br>');
}
this seems to be valid (no errors when I test). It seems that you CAN re-declare variables in JavaScript - but it probably isn't every a good idea, unless a special case - see this related question mentioning how [Google Analytics makes use of the 'safe' redeclaration of a variable] (Redeclaring a javascript variable)
there is some discussion about re-declaring variables in JS (and also loop variables like i) in this related SO question: declare variables inside or outside the loop
There is event a JavaScript pattern for single declaration of variables

Will I have any problems if I declare the same variable multiple times?

So lets say I have some code:
//Javascript
var elements = [];
function addNumbah1(){
var i = 1;
elements.push(i);
}
function addNumbah2(){
var i = 2;
elements.push(i);
}
And that goes on up to addNumbah999(), is it bad form to declare the i variable every time? Will that break anything? Should I do:
//Javascript
var elements = [];
var i
function addNumbah1(){
i = 1;
elements.push(i);
}
function addNumbah2(){
i = 2;
elements.push(i);
}
Short answer: NO, JS hoists all variable declarations to the top of the scope, regardless of how many times you've declared them:
var i = 0
for (var i=0;i<10;i++)
{
var j = i%2;//declared 10 times, on each iteration
}
Will be translated to
var i, j; //i is undefined at this point in the code.
for (i = 0;i<10;i++)
{
j = i%2;//declared 10 times, on each iteration
}
In your first example, you're declaring i as a variable in a function's scope, which is what you must do to avoid cluttering the global scope. The memory these variables use is allocated when the function is called, and deallocated when the function returns (roughly, closures form an exception, but that would take us to far). Consider this:
var i = 10;
function someF()
{
var i = 1;
alert(i);
}
someF();//alerts 1 <-- value of i, local to someF
alert(i);//10, global i is unchanged
But if you were to omit the var:
function someF()
{
i = 1;
alert(i);
}
You'll see that 1 is alerted twice. If JS can't find a variable declaration in the current scope, it will look in the higher scopes until a var is found. If no variable is found, JS will create one for you in the highest scope (global). Check my answer here on how implied globals work for a more detailed example, or read the MDN pages, especially the section on Name conflicts
Lastly, I'd like to add that globals, especially implied globals, are evil. Also know that the ECMA6 standard is clearly moving away from global variables and introduces support for true block-scopes. As you can see here
Oh, and if you want to check if a function uses implied globals: 'use strict'; is a great thing:
(function()
{
'use strict';
var localVar = 123;//ok
impliedGlobal = 123;//TypeError!
}());
As you can see, implied globals are not allowed. See MDN on strict mode for the full explanation
The second form, with global i might actually be a bit slower because it's defined in a higher scope, and variables defined in a higher scope take longer to resolve.
Aside from any performance considerations just stick with common guidelines unless performance is really an issue. In this case: scope your variables as narrowly as possible.
I would strongly advise you to use the first form.
The first way you did it is fine. Each instance of i would have no knowledge of the other i in the other functions.
You should read this tutorial on global versus local variables
Also, could I suggest an optimization. Why can't you just do the following to cover any number (instead of separate functions for each number)?
var elements = [];
function addNumbah(number){
elements.push(number);
}
It is okay to declare variables with same name in different functions.
Variables declared inside a function only exist in the scope of that function, so having the same variable name across different functions will not break anything.
In fact, it is good form to keep variables in as small of a scope as possible! Global variables can be difficult to manage and can create really bad bugs, especially if one function isn't done using the variable when another function tries to access it.
Specifically for simple variables, declaring
var i = 0;
every time is perfectly fine.
You can declare a variable multiple times..In your code you are declaring Variable i in different scopes here:
//Here you are declaring variable i local to addNumbah1,2 functions
var elements = [];
function addNumbah1(){
var i = 1;
elements.push(i);
}
function addNumbah2(){
var i = 2;
elements.push(i);
}
//Here v /variable i has been declared globally
var elements = [];
var i
function addNumbah1(){
i = 1;
elements.push(i);
}
function addNumbah2(){
i = 2;
elements.push(i);
}
Note that although you can declare a variable multiple times but generally its not a good programming practice as it may cause bugs/problems in your application

About scoping in JavaScript

I need to have some information about the scoping in JavaScript. I know that it supports lexical (static) scoping, but, does not it support dynamic scoping as well?
I think you're confused because Javascript uses static scoping but at function-level, not at block level like usual structured languages.
var foo = "old";
if (true) {var foo = "new";}
alert (foo == "new")
So be careful, blocks don't make scope!
That's why you sometimes see loops with functions inside just to enable variables whose scope is inside an iteration:
functions = [];
for(var i=0; i<10; i++) {
(function(){
var local_i = i;
functions[local_i] = function() {return local_i;}
})();
}
functions[2]() // returns 2 and not 10
As far as I understood; Javascript has two kinds of variables which are global and local variables. But, suppose we have a variable called x, which is defined as global, and defined in the static parent of the scope of place where x is referenced. In this case, x takes the value of the global variable. Thus, global variable has higher priority than local ones. And, when there is no any global variables, x finds the declaration through the static chain which makes me think that Javascirpt is staticaly scoped language.
Am I right at above?

Categories

Resources