On occasion I see Node barf when it sees code like this:
if (true) {
const z = 'foo';
} else {
const z = 'bar';
}
Node says that z has already been declared as constant. But since this is an if-else, at what point does Node actually see both declarations? Does the eval operation in Node catch this somehow?
Node 4 and 5 have incomplete support for const. One of the missing features is support for block scope outside of strict mode.
More info at this support table.
Prior to Node v6, they implemented an earlier draft of the specification, in which const variables were block scoped. Declaring two const variables in the same scope with the same name resulted in an error, however declaring a const variable in a loop behaved strangely: the constant got the value from the first assignment. Any further assignment had no effect.
for (var i = 0; i < 3; i++) {
const j = i;
console.log(j)l // prints 0 all three times in node 5.x
}
Related
I am learning about For Looops and I find that the following two pieces of code work just the same.
Code 1:
for (let i=0 ; i<bobsFollowers.length; i++){
for ( let j=0; j<tinasFollowers.length; j++){
if (bobsFollowers[i] === tinasFollowers[j]){
mutualFollowers.push(tinasFollowers[i]);
}
}
}
console.log(mutualFollowers);
Code 2
for (i=0 ; i<bobsFollowers.length; i++){
for ( j=0; j<tinasFollowers.length; j++){
if (bobsFollowers[i] === tinasFollowers[j]){
mutualFollowers.push(tinasFollowers[i]);
}
}
}
console.log(mutualFollowers);
You can globally access the variable if you do not include let keyword
for (let i = 0; i < 3; i++) {
console.log(i);
}
for (j = 0; j < 3; j++) {
console.log(j);
}
console.log('j ', j); // accesible
console.log('i ', i); // inaccesible
Yes, if you do not specifically use the let keyword in a for, for...of or for...in loops etc, they will work the same as when you use the let keyword.
However, when you don't explicitly declare using let keyword, the variable will be declared as a var. let and const are block level variables, but you also need to understand that 'functions are not the only blocks, any { } is basically a block'. i.e. Once declared a 'var' will become a function scoped variable and in case it is not inside a function, and declared outside, then it becomes globally available, which is not such a good thing considering you might have multiple for loops using a variable named 'i' and if you don't use let, it will just keep incrementing the old 'i'. Please see the below two examples to understand what I mean by the above sentence:
const test = function(){
let let1 = 1;
var var1 = 2;
{
let let1 = 9; //This is a block scoped variable limited to this { } block
var var1 = 3; //re-initialization still overrides the original var 1 variable's value because once declared, the var variable is function scoped
console.log(let1); //9 - Block Scoped
console.log(var1); //3 - Function Scoped
}
console.log(let1); //1 - Function Scoped
console.log(var1); //3 - Still Function Scoped, always function scoped
}
test();
What I meant by globally incrementing value of 'i':
for(i=0; i< 2; i++){
console.log('first loop', i)
}
for(i;i< 5; i++){//I am not initializing i to 0, but I'm just trying to show that it is a global variable now.
console.log('second loop', i)
}
for(i; i< 7; i++){ //I am not initializing i to 0, but I'm just trying to show that it is a global variable now.
console.log('third loop', i)
}
Secondly, in ES5, Strict Mode was introduced, which basically is a way you can opt out of writing 'sloppy mode' JS code, and you can use it by specifying 'use strict'; globally or at a function level. And strict mode is used in most companies and developers in their professional code bases.
The point I want to convey with this is that 'Strict Mode' does not allow you to use for loops without declaring the variable, you have to explicitely specify the 'var' or 'let' keywords. Therefore it is always a good practice to declare your variables. You can read more about strict mode here: Strict Mode
Lastly, in the current post ES6 times, using the var keyword to declare variable is not considered as a good practice due to something called as Hoisting, which basically means that before the a var x; is declared, if you try to use it, you still can, however it's value will be 'undefined'. But in case of let you cannot use a variable before you declare it. You can read more about it Here : Hoisting
Also, in case of let if you try to access a variable before it's initialized, it throws you a Reference Error. This is because of a concept called as a 'Temporal Dead Zone'. You can read more about it here: TDZ
'let' is all about lexical scope, by default variables and objects in javascript have a global scope. As other have pointed out, using var will make the scope of variable global so anything can access and modify it.
Another use case for let would be in closures.
This example is from CS50's react native lecture 0 & 1.
Here makeFunctionArray returns an array of functions which print the value of i.
function makeFunctionArray() {
const array = [];
for(var i=0; i<5; i++) {
array.push(function () { console.log(i) });
}
return array;
}
const functionArray = makeFunctionArray();
functionArray[0]();
Now, what do you expect functionArray[0]() to print?
0, right? because we're invoking the function at index zero and it should console log 0.
But it doesn't print 0, instead it prints 5.
This is because 'i' has a global scope and will have a value of 5 when loop terminates.
the function(closure) we're returning from the makeArray function will still have access to 'i' and the value 5 gets wrapped up in it while being returned. so every functionArray[index]() will print 5.
This can be avoided with 'let' if 'i' is a let, its scope will only be the 'for' loop.
At the end of this lecture, this scenario is introduced and answered in next lecture
Yes, you have to. Or the old var
As other responses mention you will populate this variable in a broader scope.
Imagine this situation, You need to create a function that print the first 10 numbers:
function printNumbers(){
for (i=0; i<10; i++) {
console.log(i)
}
}
That's cool. Now you need to invoke this function 12 times, easy right?
function printNumbers(){
for (i=0; i<10; i++) {
console.log(i)
}
}
for (i=0; i<12; i++) {
printNumbers()
}
Well, if you execute this in your google chrome console (don't). You will fry your browsers. Since i will never reach 12 and you will be in an infinite loop.
You can test this safely by changing 12 by 5, you will see that the function only runs 1 time and not 5.
So it is not for your code (only), it is for who is going to use your code in the future. You are leaving a potential big fail in your code. Imagine it is in a library.
You have a good explanation already in StackOverflow about scoping and let here: What's the difference between using "let" and "var"?
Also about scope in general here: What is the scope of variables in JavaScript?
The scope of let is restricted to that block alone. but if you do not specify let keyword it is scoped to the global environment(the global scope of the browser is window object)
{
let a = 1;
b = 2;
}
console.log(a) //error
console.log(b) //2
I've tried the babel transpiler, and it converts All let, const and var to just var, so in all, what's the difference in our code usage?
I have read documents and I know what's the difference between let, const and var, but if all of them are eventually converted to var, what's the difference? it means that there shouldn't be any meaningful differences in performance or even scope!
Update(02.14.2019) : Based on the answers I understood that scope does matter and even though they are converted to var, babel keeps the meaning of scope. My question remains about the performance, is there any meaningful difference in performance?
I've attached the input and output of the transpiler, with a more complex scenario
input:
let a = 1;
for (let a = 0; a !== 0;) {
for (let a = 0; a !== 0;) {}
}
output
"use strict";
var a = 1;
for (var _a = 0; _a !== 0;) {
for (var _a2 = 0; _a2 !== 0;) {}
}
Babel converts the ES6 syntax to ES5 syntax (or whatever source and target versions of JS you are dealing with).
This will often lose some of the nuances in the code, but you are looking at a very trivial example.
Consider this instead:
let x = 1;
{
// Inside a block, this is a different x
let x = 2;
console.log(x);
}
console.log(x);
Babel will convert that to:
"use strict";
var x = 1;
{
// Inside a block, this is a different x
var _x = 2;
console.log(_x);
}
console.log(x);
See how it renames the inner x so that it doesn't overwrite the outer one?
It expresses the effect of the ES6 as much as it can in ES5, even if the result is ugly (because the elegant feature from ES6 is not available).
Babel runs checks against each variable, and throws errors if certain procedural rules are violated. For example, if a const is defined, and the value is changed later, this would violate the type's rules. Another would be if a variable is redefined in a scope where it already exists (this could be a function of the same name). In some cases Babel simply renames things to prevent conflicts.
I was debugging my js code on Chrome Ubuntu (Version 68.0.3440.106 64 bits) and I notice that the debugger is giving me wrong values, even if I watch the value by adding a watch expression entry.
for (let i = 0; i < visibility.show.or.length; ++i) {
const currentVisibilityContext = visibility.show.or[i];
}
but if I use var instead of let it works fine
for (var i = 0; i < visibility.show.or.length; ++i) {
const currentVisibilityContext = visibility.show.or[i];
}
Can any one explain to me this behavior?
Thank you very much.
Variables declared with the var keyword can not have Block Scope.
Variables declared inside a block {} can be accessed from outside the block.
Example
{
var x = 2;
}
// x CAN be used here
Before ES2015 JavaScript did not have Block Scope.
Variables declared with the let keyword can have Block Scope.
Variables declared inside a block {} can not be accessed from outside the block:
Example
{
let x = 2;
}
// x can NOT be used here
copied without problems from W3schools ofc
That's so weird. I get this when a console snippet is fired.
Is any of the properties of visibility, a observable property (like a KO observable) by any chance. Probably the debugger stepped into the observable property viz, function and is out of scope. Since everything is in one line, you get to see that debugger is executing a single command. Please try to split the line into multiple lines, to see how it behaves.
I'm wondering what is the difference between let and const in ES6. Both of them are block scoped, as the example in the following code:
const PI = 3.14;
console.log(PI);
PI = 3;
console.log(PI);
const PI = 4;
console.log(PI);
var PI = 5;
console.log(PI);
In ES5 the output will be:
3.14
3.14
3.14
3.14
But in ES6 it will be:
3.14
3
4
5
I'm wondering why ES6 allows the change of const value, the question is why should we use 'const' now? we can use 'let' instead?
Note: jsbin can be used for testing, choose JavaScript to run ES5 code and Traceur to run it with ES6 capabilities.
The difference between let and const is that once you bind a value/object to a variable using const, you can't reassign to that variable. In other words Example:
const something = {};
something = 10; // Error.
let somethingElse = {};
somethingElse = 1000; // This is fine.
The question details claim that this is a change from ES5 — this is actually a misunderstanding. Using const in a browser that only supports ECMAScript 5 will always throw an error. The const statement did not exist in ECMAScript 5. The behaviour in is either JS Bin being misleading as to what type of JavaScript is being run, or it’s a browser bug.
In practice, browsers didn't just go from 0% support for ECMAScript 2015 (ECMAScript 6) to 100% in one go — features are added bit-by-bit until the browser is fully compliant. What JS Bin calls ‘JavaScript’ just means whatever ECMAScript features your browser currently supports — it doesn’t mean ‘ES5’ or ‘ES6’ or anything else. Many browsers supported const and let before they fully supported ES6, but some (like Firefox) treated const like let for some time. It is likely that the question asker’s browser supported let and const but did not implement them correctly.
Secondly, tools like Babel and Traceur do not make ES6 ‘run’ in an older browser — they instead turn ES6 code into ES5 that does approximately the same thing. Traceur is likely turning const statements into var statements, but I doubt it is always enforcing that the semantics of a const statement are exactly replicated in ES5. Using JS Bin to run ES6 using Traceur is not going to give exactly the same results as running ES6 in a fully ES6 specification-compliant browser.
It is important to note that const does not make a value or object immutable.
const myArray = [];
myArray.push(1); // Works fine.
myArray[1] = 2; // Also works fine.
console.log(myArray); // [1, 2]
myArray = [1, 2, 3] // This will throw.
Probably the best way to make an object (shallowly) immutable at the moment is to use Object.freeze() on it. However, this only makes the object itself read-only; the values of the object’s properties can still be mutated.
What you're seeing is just an implementation mistake. According to the ES6 spec wiki on const, const is:
A initialize-once, read-only thereafter binding form is useful and has
precedent in existing implementations, in the form of const
declarations.
It's meant to be read-only, just like it currently is. The ES6 implementation of const in Traceur and Continuum are buggy (they probably just overlooked it)
Here's a Github issue regarding Traceur not implementing const
let
Use block scope in programming.
for every block let create its own new scope which you cannot access in outside of that block.
value can be changed as many times as you want.
let is extremely useful to have for the vast majority of code. It can greatly enhance your code readability and decrease the chance of a programming error.
let abc = 0;
if(true)
abc = 5 //fine
if(true){
let def = 5
}
console.log(def)
const
It allows you to be immutable with variables.
const is a good practice for both readability and maintainability and avoids using magic literals e.g.
// Low readability
if (x > 10) {
}
//Better!
const maxRows = 10;
if (x > maxRows) {
}
const declarations must be initialized
const foo; // ERROR: const declarations must be initialized
A const is block scoped like we saw with let:+
const foo = 123;
if (true) {
const foo = 456; // Allowed as its a new variable limited to this `if` block
}
The let and const
ES6 let allows you to declare a variable that is limited in scope to the block (Local variable). The main difference is that the scope of a var variable is the entire enclosing function:
if (true) {
var foo = 42; // scope globally
}
console.log(foo); // 42
The let Scope
if (true) {
let foo = 42; // scoped in block
}
console.log(foo); // ReferenceError: foo is not defined
Using var in function scope is the same as using let:
function bar() {
var foo = 42; // scoped in function
}
console.log(foo); // ReferenceError: foo is not defined
The let keyword attaches the variable declaration to the scope of whatever block it is contained in.
Declaration Order
Another difference between let and var is the declaration/initialization order. Accessing a variable declared by let earlier than its declaration causes a ReferenceError.
console.log(a); // undefined
console.log(b); // ReferenceError: b is not defined
var a = 1;
let b = 2;
Using const
On the other hand, using ES6 const is much like using the let, but once a value is assigned, it cannot be changed. Use const as an immutable value to prevent the variable from accidentally re-assigned:
const num = 42;
try {
num = 99;
} catch(err) {
console.log(err);
// TypeError: invalid assignment to const `number'
}
num; // 42
Use const to assign variables that are constant in real life (e.g. freezing temperature). JavaScript const is not about making unchangeable values, it has nothing to do with the value, const is to prevent re-assigning another value to the variable and make the variable as read-only. However, values can be always changed:
const arr = [0, 1, 2];
arr[3] = 3; // [0, 1, 2, 3]
To prevent value change, use Object.freeze():
let arr = Object.freeze([0, 1, 2]);
arr[0] = 5;
arr; // [0, 1, 2]
Using let With For Loop
A particular case where let is really shines, is in the header of for loop:
for (let i = 0; i <= 5; i++) {
console.log(i);
}
// 0 1 2 3 4 5
console.log(i); // ReferenceError, great! i is not global
Summary:
Both the let and the const keyword are ways to declare block scoped variables. There is one big difference though:
Variables declared with let can be reassigned.
Variables declared with const have to be initialized when declared and can't be reassigned.
If you try to reassign variables with declared with the const keyword you will get the following error (chrome devtools):
Why should we use this?
If we know that we want to assign a variable once and that we don't want to reassign the variable, using the const keywords offers the following advantages:
We communicate in our code that we don't want to reassign the variable. This way if other programmmers look to your code (or even you to your own code you wrote a while ago) you know that the variables which are declared with const should not be reassigned. This way our code becomes more declarative and easier to work with.
We force the principle of not being able to reassign a variable (JS engine throws error). This way if you accidentally try to reassign a variable which is not meant to be reassigned you can detect this at an earlier stage (because it's logged to the console).
Caveat:
Although a variable declared with const can't be reassigned this doesn't mean that an assigned object isn't mutable. For example:
const obj = {prop1: 1}
// we can still mutate the object assigned to the
// variable declared with the const keyword
obj.prop1 = 10;
obj.prop2 = 2;
console.log(obj);
If you also want your object to be non mutable you can use Object.freeze() in order to achieve this.
let and const
Variables declared with let and const eliminate specific issue of hoisting because they’re scoped to the block, not to the function.
If a variable is declared using let or const inside a block of code (denoted by curly braces { }), then the variable is stuck in what is known as the temporal dead zone until the variable’s declaration is processed. This behavior prevents variables from being accessed only until after they’ve been declared.
Rules for using let and const
let and const also have some other interesting properties.
Variables declared with let can be reassigned, but can’t be
redeclared in the same scope.
Variables declared with const must be assigned an initial value, but
can’t be redeclared in the same scope, and can’t be reassigned.
Use cases
The big question is when should you use let and const? The general rule of thumb is as follows:
use let when you plan to reassign new values to a variable, and
use const when you don’t plan on reassigning new values to a
variable.
Since const is the strictest way to declare a variable, it is suggest that you always declare variables with const because it'll make your code easier to reason about since you know the identifiers won't change throughout the lifetime of your program. If you find that you need to update a variable or change it, then go back and switch it from const to let.
var declarations are globally scoped or function scoped while let and
const are block scoped.
var variables can be updated and re-declared within its scope; let
variables can be updated but not re-declared;const variables can neither be updated nor re-declared.
They are all hoisted to the top of their scope. But while var
variables are initialized with undefined, let and const variables are
not initialized.
While var and let can be declared without being initialized, const
must be initialized during declaration.
Here are some notes that I took that helped me on this subject. Also comparing const and let to var.
Here's about var:
// Var
// 1. var is hoisted to the top of the function, regardless of block
// 2. var can be defined as last line and will be hoisted to top of code block
// 3. for undefined var //output error is 'undefined' and code continues executing
// 4. trying to execute function with undefined variable
// Example: // log(myName); // output: ReferenceError: myName is not defined and code stops executing
Here's about let and const:
// Let and Const
// 1. use `const` to declare variables which won't change
// 2. `const` is used to initialize-once, read-only thereafter
// 3. use `let` to declare variables which will change
// 4. `let` or `const` are scoped to the "block", not the function
// 5. trying to change value of const and then console.logging result will give error
// const ANSWER = 42;
// ANSWER = 3.14159;
// console.log(ANSWER);
// Error statement will be "TypeError: Assignment to constant variable." and code will stop executing
// 6. `let` won't allow reference before definition
// function letTest2 () {
// log(b);
// let b = 3;}
// Error statement will be "ReferenceError: b is not defined." and code will stop executing
Var
The var keyword was introduced with JavaScript.
It has global scope.
It can be declared globally and can be accessed globally.
Variable declared with var keyword can be re-declared and updated in the same scope.
Example:
function varGreeter(){
var a = 10;
var a = 20; //a is replaced
console.log(a);
}
varGreeter();
It is hoisted.
Example:
{
console.log(c); // undefined.
//Due to hoisting
var c = 2;
}
Let
The let keyword was added in ES6 (ES 2015) version of JavaScript.
It is limited to block scope.
It can be declared globally but cannot be accessed globally.
Variable declared with let keyword can be updated but not re-declared.
Example:
function varGreeter(){
let a = 10;
let a = 20; //SyntaxError:
//Identifier 'a' has already been declared
console.log(a);
}
varGreeter();
It is not hoisted.
Example:
{
console.log(b); // ReferenceError:
//b is not defined
let b = 3;
}
Global object property
var no1 = "123"; // globally scoped
let no2 = "789"; // globally scoped
console.log(window.no1); // 123
console.log(window.no2); // undefined
Redeclaration:
'use strict';
var name= "Keshav";
var name= "Keshav Gera"; // No problem, 'name' is replaced.
let surname= "Rahul Kumar";
let surname= "Rahul Khan "; // SyntaxError: Identifier 'surname' has already been declared
Hoisting
function run() {
console.log(name); // undefined
var name= "Keshav";
console.log(name); // Keshav
}
run();
function checkHoisting() {
console.log(name); // ReferenceError
let name= "Keshav";
console.log(name); // Keshav
}
checkHoisting();
Note: in case of var, you will get undefined, in case of let you will get reference error
Const
It allows you to be immutable with variables.
Const declarations must be initialized
const name; // ERROR: const declarations must be initialized
A const is block scoped like we saw with let:+
const num = 10;
if (true) {
const num = 20; // Allowed as its a new variable limited to this `if` block
}
/*
// declaration of const in same block scope is not allowed
const a = 10;
const a = 15; //Redeclaration of const a Error
console.log(`const outer value `+a);
*/
/*
//declaration of const in different block scope is allowed
const a = 10;
console.log(`outer value of a `+a)
{
const a = 15; //Redeclaration of const allowed in different block scope
console.log(`ineer value of a `+a);
}
*/
/*
// re assigning const variable in any block scope is not allowed
const a = 10;
a = 15; //invalid assignment to const 'a'
{
a = 15; //invalid assignment to const 'a'
}
*/
/*
// let also can not be re declared in the same block scope
let a = 10;
let a = 15; //SyntaxError: redeclaration of let a
*/
/*
// let can be redeclared in different block scope
let a = 10;
{
let a = 15; //allowed.
}
*/
/*
// let can be re assigned in same block or different block
let a = 10;
a = 15; //allowed for let but for const its not allowed.
*/
/*
let a = 10;
{
a = 15; //allowed
}
*/
1. >>> const a = 2
2. >>> var a = 3
3. >>> a = 4
4. >>> a // print 2
Why the operation line 3 is allowed? const seems more "global" than without any keyword...
const scope is defined as 'block scoped' (the scope of which, is restricted to the block in which it is declared).
MDN documentation:
Constants are block-scoped, much like variables defined using the let
statement. The value of a constant cannot change through
re-assignment, and it can't be redeclared.
Regarding your specific issue:
First as comments said const is relevant in ES6. I don't know about you but i get (typing your line 2: var a = 3;): SyntaxError: Identifier 'a' has already been declared
so your example is not quite possible.
This is is just how const works (or doesn't work):
Creates a constant1 that can be global or local to the function in which it is declared. Constants follow the same scope rules as variables [.. and cannot share a name] with a function or a variable in the same scope.
Firefox [..] throws a TypeError if you redeclare2 [which is different than re-assigning] a constant. None of the major browsers produce any notices or errors2,3 if you assign another value to a constant [..] but the reassignment is unsuccessful (only) in Firefox and Chrome (at least since version 20).
Note that const is not part of the ECMAScript 5 specification and the JavaScript 1.5 semantics will be re-defined in ECMAScript 6.
Behavior will vary across browser implementations with respect to support and re-declaration/re-assignments semantics.
1 In IE 9, using const a = 2 results in
"Syntax error"
2 In FF 14, const a = 2; var a = 3; a = 4; a, when evaluated as a single program, results in
TypeError: redeclaration of const a
which is different than executing each line one-at-a-time in the REPL. I suspect this is because var is hoisted above the const and because a const "cannot share a name with a function or variable in the same scope".
3 In Chrome 21, const a = 2; var a = 3; a = 4; a evaluates to 2 with no warning or message.