Is a variable declaration the same as a variable's binding? - javascript

MDN documentation states:
let bindings are created at the top of the (block) scope containing
the declaration, commonly referred to as "hoisting". Unlike variables
declared with var, which will start with the value undefined, let
variables are not initialized until their definition is evaluated.
Accessing the variable before the initialization results in a
ReferenceError. The variable is in a "temporal dead zone" from the
start of the block until the initialization is processed.
Is the "let binding" referrred to (the hoisting of let and const) just the keyword let, or is it just the creation of storage space (which doesn't have to do with the keyword)?
Previously I thought the variable keyword and variable name together comprised a declaration, but in a question I asked recently, the answerer said they are actually an initialization.

I'm sorry for using two different terms when writing that MDN paragraph. For all purposes in that article, "variable" and "binding" should be understood as the same thing. But let's go into details.
A variable declaration creates the variable (as an abstract entity). It tells the compiler that it should introduce a new variable, and also can tell it about a name, a type to be held, an initial value, a scope etc. (depending on the language). In JS, there are different kinds of declarations that do different things, for example
var has a name, an optional initialiser and scoping rules specific to var
function has a (sometimes optional) name, the value is always given and known to be a function
const has a name, a required initialiser, should be immutable, and has lexical scoping
…
A binding is the association of a variable name with the variable entity, for example "x refers to the variable declared with class x". Such bindings depend on the scope, i.e. in every different scope there are different bindings and so the identifier x might refer to different things in different scopes.
Given the scoping rules of JavaScript, a variable declaration also causes bindings for itself to be created in the respective scopes.
So the binding is what makes the name available to be used. That's what I referred to as "the let binding is created at the top of the scope". It has nothing to do with the variable existing, having memory allocated for it, or being initialised.

A declaration just says that something exists. In JavaScript you can declare variables, functions and (more recently) classes.
In some languages (e.g. C, C++) it's possible to declare something without defining it. For example:
// this declares a function exists with a given signature, but doesn't define its implementation
void someFunction();
someFunction(); // here we call the function, since we know it exists
// here we define the function, which we have to do at some point
void someFunction() { /* ... */ }
This pattern is less common in modern languages, where the declaration and the definition tends to be combined, but it's useful to understand the distinction seeing as your question seems largely about terminology.
Variables can be declared, however they don't have definitions.
let b; // we declare that there's a variable 'b'
Instead you can assign a variable:
b = 5; // assignment
let c = 6; // declaration and assignment in one statement
The concept of binding in computer science has many forms. For example, when you type foo in your code, binding is the act of working out which variable/function/type/... should be used. In JavaScript this is pretty straightforward, but in some languages it can get pretty hairy (due to things like overload resolution and so forth).
However I don't believe that's what MDN means when they talk about let bindings. I believe it's a shorthand for "let declaration and assignment", as we saw above.
Regardless, I wouldn't worry too much about that term. The most important bit to understand from the paragraph you've quoted is that let and const are tighter versions of var, introduced in recent versions of the language to address pitfalls and surprises that came from the way var works.
Previously I thought the variable keyword and variable name together comprised a declaration
You're right.
var a;
var b = 1;
let c;
let c = 2;
const d = 3;
These are all declarations of variables (even though const technical variables can't vary, or more precisely, they cannot be reassigned).
It's just that var is a bit sloppy and surprising.
You could declare a var more than once within the same scope:
var a = 1;
var a = 2;
This won't work with let:
let a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared
Scoping on var can be surprising too:
for (var i = 0; i < 10; i++)
{
var inner = 1;
}
console.log(inner); // prints 1 even though you might think this would be an error
Or worse:
for (var i = 0; i < 10; i++)
{
for (var i = 0; i < 10; i++)
{
console.log('hello');
}
}
At a glance you might think this would print hello 100 times (10*10), but actually it is only printed 10 times because both loops use the same variable. This is a type of programmer error that the language should really prevent. If that code used let i instead, it would produce a syntax error.
As for hoisting you can think of it as though all the var declarations were moved to the top of the containing function.
function foo()
{
doThing();
var i = 0;
doSomethingElse();
for (var j = 0; j < 10; j++)
{
var k = 10;
}
}
Even though that's how you might write the code, it behaves as though you had written:
function foo()
{
var i; // all declarations hoisted to top of containing function scope
var j;
var k;
doThing();
i = 0;
doSomethingElse();
for (j = 0; j < 10; j++)
{
k = 10;
}
}
This is why you can write:
i = 10;
var i;
The var is moved up in the code, so it behaves as:
var i;
i = 10;
You can think of let as not being moved. Therefore it is an error to reference it before it is declared.

The main thing to understand here is that the js engine actually visits a let statement inntwo different situations (as well as every other statement, but it particularily matters here). It is visited once during parsing, when it generates an AST and also analyzes the scopes and the variables. It also creates a list of variables for each scope. Now when the code gets executed, the engine visits the statement a second time (or more often if its inside a loop / function / whatever) and now finally initializes the variable and assigns a value to it. So "hoisting" is basically just caused because of the parsing / executing stages, the engine knows that a variable exists before it reaches the declaration statement during execution as it has already parsed it before.
Is the "let binding" referrred to (the hoisting of let and const) just the keyword let, or is it just the creation of storage space (which doesn't have to do with the keyword)?
The keyword actually causes an entry in the scope record, which will then get turned into a storage space during execution. On the other hand the statement itself causes an initialization during execution. So its actually hard to say when a declaration happens, thats a question of words. Its common to say
That variable was declared at line 10
Its declared in that block
so wether "declaration" refers to the statement or the scope assignment is up to you :)
the answerer said they are actually an initialization.
Actually the answerer prefered to call it "initialization" and not "declaration" to not confuse readers, but well in reality its confusing as human languages are not as clearly defined as machine ones.

Related

Should we manually hoist all the JavaScript variables to the front of the function definition?

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

Mutating key inside JavaScript's for..in loop [duplicate]

What's the correct way to write a for-in loop in JavaScript? The browser doesn't issue a complaint about either of the two approaches I show here. First, there is this approach where the iteration variable x is explicitly declared:
for (var x in set) {
...
}
And alternatively this approach which reads more naturally but doesn't seem correct to me:
for (x in set) {
...
}
Use var, it reduces the scope of the variable otherwise the variable looks up to the nearest closure searching for a var statement. If it cannot find a var then it is global (if you are in a strict mode, using strict, global variables throw an error). This can lead to problems like the following.
function f (){
for (i=0; i<5; i++);
}
var i = 2;
f ();
alert (i); //i == 5. i should be 2
If you write var i in the for loop the alert shows 2.
JavaScript Scoping and Hoisting
The first version:
for (var x in set) {
...
}
declares a local variable called x. The second version:
for (x in set) {
...
}
does not.
If x is already a local variable (i.e. you have a var x; or var x = ...; somewhere earlier in your current scope (i.e. the current function)) then they will be equivalent. If x is not already a local variable, then using the second will implicitly declare a global variable x. Consider this code:
var obj1 = {hey: 10, there: 15};
var obj2 = {heli: 99, copter: 10};
function loop1() {
for (x in obj1) alert(x);
}
function loop2() {
for (x in obj2) {
loop1();
alert(x);
}
}
loop2();
you might expect this to alert hey, there, heli, hey, there, copter, but since the x is one and the same it will alert hey, there, there, hey, there, there. You don't want that! Use var x in your for loops.
To top it all off: if the for loop is in the global scope (i.e. not in a function), then the local scope (the scope x is declared in if you use var x) is the same as the global scope (the scope x is implicitly declared in if you use x without a var), so the two versions will be identical.
You really should declare local variables with var, always.
You also should not use "for ... in" loops unless you're absolutely sure that that's what you want to do. For iterating through real arrays (which is pretty common), you should always use a loop with a numeric index:
for (var i = 0; i < array.length; ++i) {
var element = array[i];
// ...
}
Iterating through a plain array with "for ... in" can have unexpected consequences, because your loop may pick up attributes of the array besides the numerically indexed ones.
edit — here in 2015 it's also fine to use .forEach() to iterate through an array:
array.forEach(function(arrayElement, index, array) {
// first parameter is an element of the array
// second parameter is the index of the element in the array
// third parameter is the array itself
...
});
The .forEach() method is present on the Array prototype from IE9 forward.
Actually, if you dislike declaration within for heading, you can do:
var x;
for (x in set) {
...
}
As mentioned in other answers to this question, not using var at all produces unnecessary side-effects like assigning a global property.
Use the one where you declare the loop variable with var. Implicitly declared variables have a different scope that's probably not what you intended.
for(var i = 0; ...)
is a commonly seen pattern but it's different from
for(int i; ...)
in C++ in that that the variable isn't scoped to the for block. In fact, the var gets hoisted to the top of the enclosing scope (function) so a local i will be effectively available both before the for loop (after the beginning of the current scope/function) and after it.
In other words, doing:
(function(){ //beginning of your current scope;
//...
for(var i in obj) { ... };
})();
is the same as:
(function(){ //beginning of your current scope;
var i;
//...
for(i in obj) { ... };
})();
ES6 has the let keyword (instead of var) to limit the scope to the for block.
Of course, you SHOULD be using local variables (ones declared with either var or let or const (in ES6)) rather than implicit globals.
for(i=0; ...) or for(i in ...) will fail if you use "use strict"; (as you should) and i isn't declared.
Using var is the cleanest way, but both work as described here: https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in
Basically, by using var you ensure that you create a new variable. Otherwise you might accidentally use a previously defined variable.
I think var is good for performance reasons.
Javascript won't look through the whole global scope to see if x already exists somewhere else.
From a general point of view, first version will be for an index that must live within loop's scope, while the other one would be any variable in the scope where loop's constructor got invoked.
If you're going to use loop's index inside for loop and this won't be required by others in next lines, better declare the variable with "var" so you'll be sure "x" is for loop's index initialized with 0, while the other one, if other "x" variable is available in this context, this will get overwritten by loop's index - that's you'll have some logical errors -.
I always use the block scoped let introduced in ES2015.
for (let x in set) {
...
}
Additional reading and examples

Using var when declaring i in a for loop [duplicate]

This question already has answers here:
"var" or no "var" in JavaScript's "for-in" loop?
(10 answers)
Closed 7 years ago.
I've seen Javascript code that has used two different ways of defining a for loop.
for (var i=0;i < x.length; i++)
But it's also been
for (i=0; i < x.length; i++)
The same thing has happened with for-in loops
for (var i in x)
and
for (i in x)
Is there any difference between declaring i as a var and just saying i? Are there advantages of doing one over the other? Is one these right way to do this? From what I can tell, they both act the same, but there has to be some difference.
Note: I'm not asking about the difference between for-in and for (i=0)
Without a var declaration somewhere in a function, references to i will be to the i property of the global object. This risks all sorts of unpredictable behavior if code in the body of the for loop invokes code (say, inside a called method) that also modifies the global i.
Note that declaring var i in the for loop initialization
for (var i = ...)
is equivalent to declaring var i; before the for loop:
var i;
for (i = ...)
In particular, the declaration of i will be hoisted to the top of the enclosing scope.
EDIT: If you enable strict mode, then you must declare your loop variables (all variables, actually). Referencing a variable that has not been declared with a var statement will result in a ReferenceError being thrown (rather than resulting in a global variable coming into existence).
JavaScript is functionally scoped. At least for now, the language does not have block level variables.
When you write for (var i=0; ... ); it is the same as
var i;
for (i=0; ... );
In the absence of "use strict"; variable declaration will be hoisted.
for (i=0; ... ); alone implies that i belongs to the global (top most) object (in browsers it's window)
Intro:
The for statement creates a loop that consists of three optional
expressions
Source: Mozilla JavaScript Docs
Background:
You are referring to initialization, which is an expression or variable declaration. It's almost always used to initialize a counter variable that allows us to iterate through a collection as you've shown.
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.
In JavaScript, variables can hold different data types, and in the case of a counter variable, JavaScript treats the variable as a number.
Answer:
The reason one can optionally declare a new variable (or not at all, as you've highlighted) is due to the nature of the JavaScript programming language. You've hit upon an important aspect of the language that deals with variables and scope.
"To var or not to var"
Please see this other post about using var or not using it at all to understand more...
What is the function of the var keyword and when to use it (or omit it)?
If you say start using "i" without saying "var" first, you should have declared the variable before your for loop.
Like:
var i;
for (i = 0; i < x; i++) {
doSomething();
}
==OR==
for(var i = 0; i < x; i++){
doSomething();
}

Should I really declare all vars in Javascript before using them?

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.

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

Categories

Resources