JavaScript: implement let-working with var - javascript

So I have a code that clone let-behavior. But I don't undestand how and why it is working. Can someone explain it?
(function() {
var a = 2;
})()

let is scoped to the block it appears in.
var is scoped to the function it appears in.
By replacing a block with a function (which is immediately invoked) var is scoped to the same lines of code as let would be.

Where you can only use var variables but you want to ensure that a variable declaration is not going to overwrite another pre-existing variable of the same name, you can use an IIFE to scope that variable to the function. This in effect creates a "block", similar to the second example below.
var variables are scoped to functions:
var a = 1;
let b = 1;
(function() {
var a = 2;
let b = 1;
})();
console.log(a); //=> 1 (a is not overwritten because the second `var a` is function-scoped)
console.log(b); //=> 1
let variables are scoped to blocks:
let a = 1;
var b = 1;
{
let a = 2;
var b = 2;
}
console.log(a); //=> 1 (a is not overwritten as let is block-scoped)
console.log(b); //=> 2 (b is overwritten as var is not block-scoped)
It's worth mentioning that you can redeclare a var variable, hence why it would be possible to overwrite an existing var variable of the same name. However, you cannot redeclare a let variable:
var a = 1
// will not error as `var` does not prevent redeclaration
var a = 2
let b = 1
{
// will not error as `b` is not declared in this block
let b = 2
}
// will error as `b` is already declared in this scope
let b = 3
You can read more about let and var in this question and its answers.

Related

Why can't I declare functions or variables at the block statement? [duplicate]

console.log(a) //output:ƒ a(){}
var a = 1;
function a(){};
var a = 10;
console.log(a) //output:10
====================
var a = 1;
if(true){
function a(){};
var a = 10;
}
console.log(a) // this code throws Uncaught SyntaxError: Identifier 'a' has already been declared
both above code snippets are same except the if block.why does the latter throws error when its permissible in javascript to delcare same variable twice in the same scope with var as below
function a(){};
var a = 10; //no error
Also for a slightly different scenario after removing var from `var a = 10 in the above code ,then it works fine but output is surprising
var a = 1;
if(true) {
function a(){};
a = 10;
}
console.log(a) //output:ƒ a(){}
I am surprised to see this output as I am expecting 10 ..because two variables declared inside the if block refer to the same variable declared above as javascript var doesnt respect block scope but functional scope...so why not the output for above should be 10?
where as the below code outputs 10 as i expected when replaced the function definition with function expression.
var a = 1;
if(true) {
var a = function(){ console.log() }
a = 10;
}
console.log(a) //output:10
This is surprising as javascript var doesn't respect block scope but functional scope...
Sure, but you didn't use var for the declaration of a in the block scope. You used a function declaration, which does respect block scopes (otherwise it would be completely invalid code, as in ES5 strict mode).
It's permissible in javascript to declare same variable twice in the same scope with var as below
Same applies here. The function declaration in the block uses ES6 declaration semantics (like let or const), which does not allow redeclarations.
Case 1
console.log(a) //output:ƒ a(){}
var a = 1;
function a(){};
var a = 10;
console.log(a) //output:10
Will be rendered as
var a;
a = function(){}; // now a holds the value as a function
console.log(a); // output : f a(){}
a = 1; // a is a var that holds value 1
a = 10; // a is a var that holds value 10
console.log(a); // output : 10
Case 2
var a = 1;
if(true){
function a(){};
var a = 10;
}
console.log(a)
Will be rendered as
var a;
a = 1;
if(true) {
a = function() {};
let a; // The function declaration in the block uses ES6 declaration semantics (like let or const), which does not allow re-declarations.
var a; // throws Uncaught SyntaxError: Identifier 'a' has already been declared
a = 10;
}
console.log(a);
Case 3
var a = 1;
if(true){
function a(){};
a = 10;
}
console.log(a)
Will be rendered as
var a;
a = 1;
if(true) {
a = function() {};
let a;
a = 10;
}
console.log(a); // output : f a(){}
Case 4
var a = 1;
if(true){
var a= function(){console.log()}
a = 10;
}
console.log(a)
Will be rendered as
var a;
a = 1;
if(true) {
a = function(){console.log()}
a = 10;
}
console.log(a) // output:10
Case 5
var a = 1;
if(true){
function a(){};
a = 10;
console.log(a)
}
console.log(a)
Will be rendered as
var a;
a = 1;
if(true){
a = function() {};
let a;
a = 10;
console.log(a); // output:10
}
console.log(a); // output : f a(){}
The simple solution to this is to use IIFE
(function() {
var sahil = {
checkThis: function() {
console.log(this);
function checkOther() {
console.log(this);
}
checkOther(); // checkThis() function called in "global context", will
// return "this" as "window"
}
};
var moo = sahil.checkThis;
moo(); // moo() function called in "global context", will return "this" as "window" })();

ReferenceError: variable is not defined 1 [duplicate]

This question already has answers here:
Are variables declared with let or const hoisted?
(7 answers)
Closed 3 years ago.
First off, not a duplicate, I did look at the other "ReferenceErrors" here on SO. However, my problem is not scope related nor a misspelling.
My issue is that copy apparently isn't defined despite I clearly defined it at the very first line. What is going on?
My goal is to redefine the variable copy inside the loop.
var copy = 'test 1';
for (let i = 0; i < 2; i++) {
let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
console.log(t); // Output: 'test 2';
let copy = t; // <-- ReferenceError: copy is not defined
}
I guess the issue here is you are trying to declare twice the copy variable in the loop:
let copy = t;
The solution is to remove let from your for loop as the following:
var copy = 'test 1';
for (let i = 0; i < 2; i++) {
let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
console.log(t);
copy = t; // removed let
}
So you are not declaring twice the copy variable.
Additionally I recommend to read the What's the difference between using “let” and “var”? titled article.
This is happening because of the temporal dead zone, you declare copy using let which has a block scope so in this case it is limited to the scope of the for loop.
now inside the for-loop you are trying to access copy thinking that it is the outer variable declared using var but it is not so, it is actually referring to the inner copy declared using let.
Variables declared using let are not hoisted to the top and cannot be used before declaration. This phenomenon is known as temporal dead zone.
The same is true for variable declared using const.
for (let i = 0; i < 2; i++) {
let t = copy.replace(/(\d+)/,... //copy is actually not available here, accessing it here will result in a ReferenceError
...
let copy = t; //copy will be available after this declaration
To fix it, don't declare it again with let, just re-assign the outer variable:
(function(){
var copy = 'test 1';
for (let i = 0; i < 2; i++) {
let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
console.log(t);
copy = t; //copy is the outer variable
}
})();
This is a Temporal dead zone (TDZ) issue.
In your loop, copy is hoisted to the top of the loop. However, instead of being undefined, like var, it is "not initialized" and accessing it throws an error.
var copy = 'test 1';
for (let i = 0; i < 2; i++) {
// copy is hoisted here
// It is not initialized
//Accessing copy here throws ReferenceError
let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
console.log(t); // Output: 'test 2';
let copy = t; // <-- ReferenceError: copy is not defined
}
The reason this is happening is because you declare copy twice but this is only half of the truth.
Look This code will work. Note that you declare the copy twice. But this will not throw will undefined error
var copy = 'test 1';
for (let i = 0; i < 2; i++) {
let copy = t;
}
While this will surely throw an error
var copy = 'test 1';
for (let i = 0; i < 2; i++) {
let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
let copy = t;
}
This is because of the let copy. let copy's scope is inside the for loop.
Compiler will always try to find the variable that is closest to the function you called.
hence undefined error will throw. In your case, your trying to call the var copy but the compiler found the let copy that's why it returning error not on the let copy itself but in these lines
let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
you can use it like this:
var copy = 'test 1';
for (let i=0; i<2; i++) {
let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
console.log(t); // Output: 'test 2';
copy = t; // <-- ReferenceError: copy is not defined
}
Or use a new variable name like: let copy1
To avoid ReferenceError

Block scoping with nested var shows different errors

I'm trying to understand block scoping on ES6 and found the following issue (maybe I'm just misunderstanding the concept):
In the first test I tried the following and got the commented error:
{
const x = 2;
console.log( x ); //2
{
let x = "b";
console.log(x); //b
{
var x = true; //Identifier 'x' has already been declared
}
}
}
console.log(x)
But when I try to get the type of the "already declared" x I get :
{
const x = 2;
console.log( x ); //2
{
let x = "b";
console.log(x); //b
{
console.log(typeof x); //this throws Uncaught ReferenceError: x is not defined
}
}
}
console.log(x);
I'll keep trying to see what is going on, any ideas are accepted.
Actually, your error comes from the final console.log(x);. Removing that line makes your code work fine.
This error makes perfect sense. x is only defined in inner blocks; it doesn't exist in the outer scope.
First of all, you need to know the difference between let and var
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. An explanation of why the name "let" was chosen can be found here.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
Second, you got this error "Identifier 'x' has already been declared" because you already have "let x" so you can't use "var x". However, if you change the var to let, it will work.
Example to understand scoping:
function test() { // first scope
let x = 1;
let y = 2;
console.log(x, y); //1 2
function test2() { // second scope
let x = 2;
let z = 3;
console.log(x,y,z); //2 2 3
}
test2();
console.log(z); //z is not defined... notice z is defined in the second scope, not the first one
}
test();
Keep in mind, you can access variables from higher/global scopes in inner scopes, but you can't access variables from inner scopes in higher/global scopes.
Read this: What is the scope of variables in JavaScript?
EDIT:
If you do this, it should work fine
const x = 2;
console.log( x ); //2
{
let x = "b";
console.log(x); //b
{
x = true;
}
}
console.log(x)
OR
const x = 2;
console.log( x ); //2
{
let x = "b";
console.log(x); //b
{
let x = true;
}
}
console.log(x)

JavaScript code executing after return

In the following example, JavaScript seems to be completely ignoring my return statement, and just carrying on executing code.
var x = 1;
(function() {
x = 2;
return;
var x = 3;
})();
console.log(x); // Outputs 1 in both Chrome and FF
Surely the code should output 2? If I remove the var keyword from var x = 3, it outputs 2 as expected. Is there some strange compiler optimization at work here?
No, the code shouldn't output 2 because variable declarations are hoisted so your code is equivalent to
var x = 1;
(function() {
var x;
x = 2; // changes the internal x variable
return;
x = 3; // does nothing because it's not reached
})();
console.log(x); // Outputs the outside x, which is still 1
The line
x = 2;
only changes the internal x variable which shadows the outside one.
The scope of a non global variable is the entire function in which it is declared. From the start of this function to its end.

Assigning the variable name to the same variable name

On executing
var a=b=c=d=e=f=a;
//no error(a has not initialize before)
var x=y;
//ReferenceError: y is not defined
How can the first code just execute as if a has already been initialize before.
It's because of variable hoisting. var x = EXPR; is actually converted to this:
// beginning of the block (function/file)
var x; // === undefined
// ...
// the actual position of the statement
x = EXPR
For your example this means:
var a; // === undefined
a = b = c = d = e = f = a;
Note that only a is declared using var - so you are creating tons of globals which is always a bad thing!
Your first statement is like
var a = undefined;
a = window.b = window.c = window.d = window.e = window.f = a;
where a is defined, and others are global scoped . suppose you execute a function .
(function(){
var a=b=c=d=e=f=a;
b = 10;
}());
the b can accessed outside .
in second var x=y , y is not defined yet

Categories