JavaScript has three types of scopes: global scope, function scope, and block scope. Connects to var, let, and const. Read on hoisting to clear more confusions that arise due to declaration.

1. Global Scope

Variables declared outside any function or block have global scope. They can be accessed from anywhere in the code. This can be declared using either of var, const, or let.

var globalVar = "I'm a global variable";
 
function testGlobal() {
    console.log(globalVar);  // Accessible here
}
 
testGlobal();
console.log(globalVar);  // Accessible here too
 

2. Function Scope

Variables declared inside a function with var are scoped to the function. They cannot be accessed outside the function.

function testFunctionScope() {
    var functionScopedVar = "I'm a function-scoped variable";
    console.log(functionScopedVar);  // Accessible here
}
 
testFunctionScope();
console.log(functionScopedVar);  // Uncaught ReferenceError: functionScopedVar is not defined
 

3. Block Scope

Variables declared inside a block (a pair of curly braces {}) with let or const are scoped to that block. They cannot be accessed outside the block. The example below doesn’t even use a function, it uses an if condition.

if (true) {
    let blockScopedVar = "I'm a block-scoped variable";
    const anotherBlockScopedVar = "I'm also a block-scoped variable";
    console.log(blockScopedVar);  // Accessible here
    console.log(anotherBlockScopedVar);  // Accessible here
}
 
console.log(blockScopedVar);  // Uncaught ReferenceError: blockScopedVar is not defined
console.log(anotherBlockScopedVar);  // Uncaught ReferenceError: anotherBlockScopedVar is not defined
 

var vs. let

This is where it gets tricky/confusing. The best way to remember this is through few examples. In general, don’t use var unless for some reason really required.

This example shows the difference between var and let . Or in other words, function scope and block scope.

function myFunction() {
    let x = 10;  // x is block-scoped to the function block
    if (true) {
        let y = 20;  // y is block-scoped to the if block
        console.log(x);  // 10, accessible within the function block
        console.log(y);  // 20, accessible within the if block
    }
    console.log(x);  // 10, still accessible within the function block
    // console.log(y);  // Uncaught ReferenceError: y is not defined
}
 
myFunction();
 

The following example shows why var gets confusing and should be avoided.

var items = ['apple', 'banana', 'cherry'];
 
for (var i = 0; i < items.length; i++) {
    console.log('Inside loop:', i, items[i]);
}
 
console.log('Outside loop:', i);  // i is accessible here and its value is items.length which is 3 in this case

Firstly loop stops when i is 2 but its incremented to 3 so it prints as such. As it was not bound by any functions, it kinda behaves as a global variable being accessible anywhere.