Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is block scope function ECMAScript 6 compare with ECMAScript 5 [duplicate]

Tags:

javascript

What is block scope function in ECMAScript 6?

Can anyone help me understand the main difference in the block scope function compared to ECMAScript 5?

like image 482
nihar jyoti sarma Avatar asked Jan 02 '16 09:01

nihar jyoti sarma


1 Answers

The new let and const in ES2015 (aka "ES6") have four major differences compared with the venerable var:

  1. They have block scope

  2. They aren't hoisted (well, they're sort of hoisted, but in a useful way)

  3. Repeated declarations are errors

  4. When used at global scope, they don't create properties of the global object (despite creating global variables; this is a new concept as of ES2015)

(For what it's worth, this is covered in detail in Chapter 2 of my recent book JavaScript: The New Toys, which covers ES2015-ES2020.)

Block scope

var variables exist throughout the function they're declared in (or globally, if declared globally), they aren't confined to the block they're in. So this code is valid:

function foo(flag) {
    a = 10;
    if (flag) {
        var a = 20;
    }
    return a;
}
console.log(foo(false)); // 10
console.log(foo(true));  // 20

a is defined regardless of whether flag is true and it exists outside the if block; all three as above are the same variable.

That's not true of let (or const):

function foo(flag) {
    if (flag) {
        let a = 10;
    }
    return a;           // ReferenceError: a is not defined
}
console.log(foo(true));

a only exists inside the block it's declared in. (For for statements, a declaration within the () of the for is handled very specially: a new variable is declared within the block for each loop iteration.) So outside the if, a doesn't exist.

let and const declarations can shadow declarations in an enclosing scope, e.g.:

function foo() {
    let a = "outer";

    for (let a = 0; a < 3; ++a) {
        console.log(a);
    }
    console.log(a);
}
foo();

That outputs

0
1
2
outer

...because the a outside the for loop isn't the same a as the one inside the for loop.

Hoisting

This is valid code:

function foo() {
    a = 5;
    var a = a * 2;
    return a;
}

Bizarre-looking, but valid (it returns 10), because var is done before anything else is done in the function, so that's really:

function foo() {
    var a;             // <== Hoisted

    a = 5;
    a = a * 2;         // <== Left where it is
    return a;
}

That's not true of let or const:

function foo() {
    a = 5;            // <== ReferenceError: a is not defined
    let a = a * 2;
    return a;
}

You can't use the variable until its declaration. The declaration isn't "hoisted" (well, it's partially hoisted, keep reading).

Earlier I said

  1. They aren't hoisted (well, they're sort of hoisted, but in a useful way)

"Sort of"? Yes. A let or const declaration shadows an identifier throughout the block in which it appears, even though it only actually takes effect where it occurs. Examples help:

function foo() {
    let a = "outer";

    for (let x = 0; x < 3; ++x) {
        console.log(a);            // ReferenceError: a is not defined
        let a = 27;
    }

}

Note that instead of getting "outer" in the console, we get an error. Why? Because the let a in the for block shadows the a outside the block even though we haven't gotten to it yet. The space between the beginning of the block and the let is called the "temporal dead zone" by the spec. Words aren't everybody's thing, so here's a diagram:

TMZ

Repeated declarations

This is valid code:

function foo() {
    var a;

    // ...many lines later...
    var a;
}

The second var is simply ignored.

That's not true of let (or const):

function foo() {
    let a;

    // ...many lines later...
    let a;                     // <== SyntaxError: Identifier 'a' has already been declared
}

Globals that aren't properties of the global object

JavaScript has the concept of a "global object" which holds various global things as properties. In loose mode, this at global scope refers to the global object, and on browsers there's a global that refers to the global object: window. (Some other environments provide a different global, such as global on NodeJS.)

Until ES2015, all global variables in JavaScript were properties of the global object. As of ES2015, that's still true of ones declared with var, but not ones declared with let or const. So this code using var at global scope, on a browser, displays 42:

"use strict";
var a = 42; // Global variable called "a"
console.log(window.a); // Shows 42, because a is a property of the global object

But this code shows undefined for the properties, because let and const at global scope don't create properties on the global object:

"use strict";
let a = 42; // Global variable called "a"
console.log(a); // 42 (of course)
console.log(window.a); // undefined, there is no "a" property on the global object
const q = "Life, the Universe, and Everything"; // Global constant
console.log(q); // "Life, the Universe, and Everything" (of course)
console.log(window.q); // undefined, there is no "q" property on the global object

Final note: Much of the above also holds true if you compare the new ES2015 class (which provides a new, cleaner syntax for creating constructor functions and the prototype objects associated with them) with function declarations (as opposed to function expressions):

  • class declarations have block scope. In contrast, using a function declaration within a flow-control block is invalid. (It should be a syntax error; instead, different JavaScript engines handle it differently. Some relocate it outside the flow-control block, others act as though you'd used a function expression instead.)
  • class declarations aren't hoisted; function declarations are.
  • Using the same name with two class declarations in the same scope is a syntax error; with a function declaration, the second one wins, overwriting the first.
  • class declarations at global scope don't create properties of the global object; function declarations do.

Just as a reminder, this is a function declaration:

function Foo() {
}

These are both function expressions (anonymous ones):

var Foo = function() {
};
doSomething(function() { /* ... */ });

These are both function expressions (named ones):

var Foo = function Foo() {
};
doSomething(function Foo() { /* ... */ });
like image 97
T.J. Crowder Avatar answered Sep 22 '22 01:09

T.J. Crowder