Run below code in Node environment. Running it in browser console doesn't allow to redeclare variable of var.
console.log(a);
var a = 5;
According to hoisting, the above code is going to look like this
var a = undefined;
console.log(a); // undefined
a = 5;
a variable is being hoisted to the top of the file. JS Engine allocates memory for this variable before the execution. The question is why below code consols 5 instead of undefined.
var a = 5;
console.log(a);
var a = 6;
I'm looking at this code and imagining that it's going to look like this:
var a = 5;
var a = undefined;
console.log(a); // undefined
a = 6;
I'd like to be sure of the answer instead of guessing. The JS Engine is smart enough to see that a variable is already declared and is going to ignore the next var expression and rehoisting in such case? So the output should be looking like:
var a = 5;
console.log(a); // 5
a = 6;
So it's like:
JS Engine sees for the first time declaration (in this case along with initialization) of a variable so it's allocating memory.
JS Engine sees for the second time declaration of a variable but is going to ignore the hoisting because variable of given name is already in the memory.
Am I wrong in something?
Preface: In modern JavaScript, var should never be used. Use let or const.
The JavaScript engine handles var in two steps:
Upon entering the global scope or a function scope, it processes every var in the entire scope, defining variables for the them initialized wit the value undefined. If a variable is declared more than once with var, it's exactly as though it were declared once.
Then it starts the step-by-step execution of the code. In that step-by-step execution, any initializer on a var statement (the = 5 in var a = 5) is considered an assignment. So var a = 5 is treated exactly like a = 5 at this point.
So in your example:
var a = 5;
var a = undefined;
console.log(a); // undefined
a = 6;
It's as though you had written this:
var a = 5;
a = undefined;
console.log(a); // undefined
a = 6;
or this:
a = 5;
var a = undefined;
console.log(a); // undefined
a = 6;
or this:
a = 5;
a = undefined;
console.log(a); // undefined
var a = 6;
or this:
var a;
a = 5;
a = undefined;
console.log(a); // undefined
a = 6;
or this:
a = 5;
a = undefined;
console.log(a); // undefined
a = 6;
var a;
or even this (but please don't! :-) ):
var a = 5;
var a = undefined;
console.log(a); // undefined
var a = 6;
var a;
That is, first all the variables declared with var are created (and only once), then the code runs as though any initializers on them were assignments.
This is not how let, const, and class declarations are handled (collectively: lexically-scoped declarations). First: Multiple declarations in the same scope are an error (including if one of them is with var and the other is with one of the lexically-scoped ones). Second: They're hoisted (in Step 1 above), but the hoisted binding¹ is uninitialized until the declaration is executed in the step-by-step code, at which point it's initialized (either with the value from the initializer, or with undefined if it's just e.g. let a;). The time between entry to the scope and the point the binding is initialized is called the Temporal Dead Zone. var doesn't have it because var variables are initialized when they're created (with the value undefined), but let, const, and class declarations do.
¹ The term binding is the general term for variable-like things. In the code:
function example(p) {
var v;
let l;
const c = 42;
function f() {
}
class C {}
}
the bindings created upon entering the example function's scope are p (a parameter), v (a var variable), l (a let variable), c (a const constant), f (the binding created by a function declaration), and C (the binding created by a class declaration). (Note: function and class expressions are handled slightly differently.)
Related
Is it common practice (or at least syntactically valid across browsers and implementations of JS) to abuse RTL associativity of assignment operators so that one can define two variables (with the first being an object) so that the second is assigned to a (newly) named property of that object which is itself assigned to another value, so that a SyntaxError() is not generated?
I know that sounds complicated, but here is the code:
var x = {}, y = x.l = 9; // generates no errors
console.log(x.l, y); // 9 9
Since:
var t = {}, t.l = 9; // Syntax Error, no doubt because t is already defined
The line:
var x = {}, y = x.l = 9;
effectively becomes:
var x = {};
var y = x.l = 9;
which is processed as:
// Parse phase
var x; // assigned the value undefined
var y; // assigned the value undefined
// Execution phase
x = {};
x.l = 9;
y = x.l;
Noting that in an assignment expression, the value on the right is assigned to the expression on the left. Compound assignments are evaluated left to right, but assigned from right to left, hence x.l = 9 is assigned before y = x.l, even though it's on the right.
Now try that with the second example:
var t = {}, t.l = 9;
becomes:
// Parse phase
var t; // assigned the value undefined
var t.l; // syntax error, stop
The var keyword at the start of a statement means the next thing must be a valid identifier. t.l is not a valid identifier (it can only be interpreted as an identifier followed by a dot property accessor), so that's it. Everything stops.
You need to use the semicolon - that's what the error says the parser expects:
var t = {};
t.l = 9;
console.log(t);
What I get from previous posts and articles is that the exports object is located on the global object. I came across this code which confused me:
let blue = 'blue'
let red = 'red'
var exports = module.exports = {
red,
blue
};
This code sets module.exports to a variable called exports which then gets set to an object which gets exported.
I am confused however by this syntax:
Example1:
var exports = module.exports = {}
How does this work exactly? Because normally in JS you can't assing a variable two times. For instance this gives an error:
Example2:
let foo = 5 = 4;
How does the code in example 1 give no error while the code in example 2 does?
let foo = 5 = 4;
Cause its parsed from right to left:
let foo = (5 = 4);
And 5 is not a variable, so you cant assign stuff to it. However it works with an identifier:
let bar;
let foo = bar = 5;
Your interpretation of what the line is doing is incorrect.
This code sets module.exports to a variable called exports which then gets set to an object which gets exported.
What is actually happening is that the value { red, blue } is being assigned to module.exports, and then that same value ({ red, blue }) is being assigned to exports.
In JavaScript and other languages with similar syntax (C, C++, C#, Java) someAssignableThing = someValue is treated as an expression, and you can use a = b as a sub-portion of other expressions and chain as many together as you want.
As an expression someAssignableThing = someValue equates to "assign someValue to someAssignableThing and evaluate to the value someValue".
So the statement:
a = b = c = d = e = 5;
would assign the value 5 to a, b, c, d, and e.
It is a syntax error to have something on the left side of the = that cannot be assigned a value and that's why you get an error in the second case (you cannot assign a value to 5).
This question already has answers here:
What is the difference between "let" and "var"?
(39 answers)
let keyword in the for loop
(3 answers)
Closed 5 years ago.
As far as I know, 'let' is used for declaring block variable. But it can't declare twice with same name. For example:
'use strict';
let a = 1;
let a = 2; // syntax error
So how to separate each scope in 'for' iteration with the same variable name?
'use strict';
for(let i = 0; i < 3; i++){
setTimeout(function(){
console.log(i);
});
}
// output:
// 0
// 1
// 2
Dose interpreter change the variable name silently? Any info will be appreciated.
I don't think is a duplicated question. Because I really want to ask is the conflict between two theory.
let scopes your variable to the block it's in.
After you've assigned a scope to a, you can't overwrite it. So the second time you use let, it can't handle that.
Correct usage would be:
'use strict';
let a = 1;
a = 2;
In the for loop , i is declaring at the beginning only and in each iteration it change the value of it .
let is used to variable that you will write there value again .
In the first example you define variable with name 'a' so you cant define another with same name , but you can change it value , which happened in the for loop.
'use strict';
let a = 1;
let a = 2; // syntax error
'use strict';
let a = 1;
var a = 2; this will overwrite...
here you specified a value already.. your intention is , it shouldn't change in runtime. so you cant able to change it once declared in block with same type let ..
that why you getting this error..
intention of let is value should not change..
in loop ,
it will be separate on iterate.. so it print value on runtime. so it wont overwrite it...
let allows to create the variable once, but the value of the variable can be changed,
example -
let t =5//
let t = 6 // throws an errow but
t =7
console.log(t) - gives 7
In the loop the variable is not declared again but only its value is incremented.
It is similar to the following:
'use strict';
let i = 0;
i = i + 1;
consider the code being iterated again and again until the condition fails.
for(let i = 0; i < 3; i++){
// code
}
step:
let i = 0
checkout i<3
exec code
i++, equals i = i + 1 // not occur error, while let i = i + 1 will occur exception
loop step-2 until i<3 == false
In your first example the variable a is defined twice in the same scope. This gives you an error because the variable already exists. let doesn't allow this, redeclaring with var does. This is one advantage of using let.
var a = 3;
var a = 2;
console.log(a); // 2
let b = 3;
let b = 2; //syntax error
let c = 3;
var c = 2; //also a syntax error
In a for loop, the i variable has a different scope. Meaning these two i variables here aren't the same.
let i = "my string";
console.log(i); //my string
for(let i = 1; i <= 3; ++i){
console.log(i); //1, 2, 3
}
console.log(i); //my string
The javascript runtime doesn't care if your variable is named the same. It will differentiate the scope and thus the reference to the variable. It's replacing your reference to i whichs value is 4 to the new variable in the for loop.
I have an answer on here on Stackoverflow which describes how the Android compiler doesn't care about your variable names. It's the same here, the runtime uses different "names" (different memory addresses).
I have been using python for a while now, and have just started learning javascript. In javascript you can, as I understand it, declare a variable without assigning a value to it (var cheese compared to var cheese = 4) in what situation would you want to declare a variable but not assign a value to it straight away?
Consider this snippet.
if (someCondition) {
var x = 5;
} else if (someOtherCondition) {
var x = 4;
}
if (x) {
doFunc();
}
Since x needs to exist for the doFunc to run, you simply add an undefined declaration above. var x; so that the if (x) doesn't return an error.
You do this when you want the value of the variable to be undefined.
var cheese;
console.log(cheese); // undefined
It's simpler than
var cheese = undefined;
The undefined value doesn't seem much useful, but this will allow to assign some other value later.
var cheese; can be perfectly useful (even if you never assign anything to it). Of course it's a shorter way to type var cheese = undefined;, but that's not the only reason…
Using var declares a local variable, and this has a nice property: it hides variables from parent scopes.
There's another part to your question:
If we're going to assign a value to var cheese anyway: why not assign immediately?.
Answer: it may be fine for your algorithm to return cheese without ever assigning anything to it — i.e. "undefined is valid".
Here's an example which illustrates how var hides variables from parent scopes:
var a = 3;
console.log(a); // prints 3; "a" is defined in this scope
function findEvenNumber(numbers) {
var a; // we declare this local variable, to ensure that we do _not_ refer to the variable that exists in the parent scope
numbers.forEach(function(number) {
if (number % 2 === 0) {
a = number;
}
});
return a; // if no even number was found, it returns undefined (because we never assigned anything to a)
}
findEvenNumber([1, 2]); // returns 2;
console.log(a); // prints 3; the "a" in this scope did not get overwritten by the function
Speculation: maybe the var cheese; syntax exists in ECMA to enable programmers to declare all variables at the beginning of their function. Such a convention was enforced by the C89 compiler, and some people grew fond of it.
I modified the original script from the MDN website given below.
What is the type of var? Is the type assigned only after a value is assigned to a variable.
Does var b = 1 overwrite the previous statement var b = 10? Or just the variable b?
Is let a non-standard language feature? I read here that it is supported in ECMAScript 6.
var a = 5;
var b = 10;
if (a === 5) {
let a = 4; // The scope is inside the if-block
var b = 1; // The scope is inside the function
alert(a); // 4
alert(b); // 1
}
alert(a); // 5
alert(b); // 1
What is the type of var?
var has no type. It's a keyword used to declare variables.
Is the type assigned only after a value is assigned to a variable?
When you declare a variable but don't assign any value to it, its value will be undefined, whose type is Undefined.
Does var b = 1 overwrite the previous statement var b = 10? Or just the variable b?
Variable statements are hoisted to the top. That means that those are equivalent:
// ...
var b = 10;
if(cond) var b = 1;
var b;
// ...
b = 10;
if(cond) b = 1;
So, since b was already declared, var b = 1 will be equivalent to b = 1.
Is let a non-standard language feature? I read here that it is supported in ECMAScript 6.
let was introduced in JavaScript 1.7, and was not part of any ECMA-262 standard at the time.
Now ECMAScript 6 has standardized it (in a bit different way than JS 1.7). However, be aware that ECMAScript 6 is still a draft.
Yes, var x has no type. var x = 1 has a type of number.
var b doesn't overwrite the other statement, it just sets a new variable for the given scope. It means within that scope you get the newly assigned value for b.
let is es6. So yes and no, depending on where your code is running.