JavaScript Scopes

K - Jul 9 '17 - - Dev Community

If you started working with JavaScript before the release of ES2015, you are probably used to the fact, that JavaScript variables are function-scoped and hoisted etc.. With ES2015, you get a new way to define variables that are block-scoped.

Before ES2015

Back in the days var was the keyword of choice to define a local variable, if you didn't use var and used a new indentifier for assignment, you could create a global variable, sometimes even by accident, if you didn't use the "use strict"; statement.

function () {
    // Global variable
    newIdentifier = 5;

    // Local variable
    var variable = 6;

    // Assignment to the defined variable
    variable = 8;

    // Another global variable (by accident)
    varialbe = 8; 
}
Enter fullscreen mode Exit fullscreen mode

Your local variables were scoped by the function in which they were defined.

// You could write something like this:
function (x) {
    if(x > 2) {
    var y = 10 * x
    }

    return y
}

// But behind the scenes it would be treated as this:
function (x) {
    var y
    if(x > 2) {
    y = 10 * x
    }

    return y
}
Enter fullscreen mode Exit fullscreen mode

This lead many developers to define all the local variables at the top of the function, because they would end up there anyway.

Since ES2015

With the release of ES2015 JavaScript got many new features, one of them block scoped variables. There are two kind of them, let and const variables.

// So this wouldn't work:
function (x) {
    if(x > 2) {
    let y = 10 * x
    }

    return y
}
Enter fullscreen mode Exit fullscreen mode

In the example, y is only accessible inside the if-block, which is the default behavior of many other languages.

What this allows you to do is define variables where they are needed and scope them with code blocks.

// Every time you see a { and } you're creating a new block
// and in there you can create a new variable scoped to that block
while(...) {
    let x = 10;
}

for(...) {
    let x = 12;
}

if (...) {
    let x = 9;
} else {
    let x = 8;
}

try {
    let x = 1;
} catch (e) {
    let x = 99;
}
Enter fullscreen mode Exit fullscreen mode

You can even use {} on their own for scoping, to keep the vars as local as possible.

function () {
    let varForTheWholeFunction = 10;

    {
    let scopedVar = getData();
    varForTheWholeFunction = parse(scopedVar);
    }
    // scopedVar isn't accessible here
    ...
    {
    let scopedVar = filterData(varForTheWholeFunction);
    varForTheWholeFunction = sortData(scopedVar);
    }

    return varForTheWholeFunction;
}
Enter fullscreen mode Exit fullscreen mode

This can be used for switch statements too.

function () {
    let a;

    switch(x) {
    case "getData": {
        let y = getData();
        a = parse(y);
    } break;
    ...
    default: {
        let y = "defaultData";
        a = parse(y);
    }
    }

    return a;
}
Enter fullscreen mode Exit fullscreen mode

So what about const? Well, their scoping works like with let, but a value has to be assigned at definition time and it can't change later, only if the function, in which this local variable is declared, is called again.

function (x) {
    if (x > 2) {
    // This will fail:
    const a;

    // This will also fail:
    const a = 1;
    a = 2;
    }
}
Enter fullscreen mode Exit fullscreen mode

So it's a variable that can only be set once, but be careful:

function () {
    // This would work:
    const x = {y: 1};
    x.y = 2;
}
Enter fullscreen mode Exit fullscreen mode

Indirections aren't save from mutation.

Conclusion

With let and const JavaScript got a way to define scopes more fine granular, which enables developers to limit code dependencies even more.

The cost of this is added complexity to the language, but on the other hand, you don't have to use all of the features that exist :)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .