infinnie / infinnie.github.io

https://infinnie.github.io/
Apache License 2.0
0 stars 1 forks source link

The reason why block scope is considered harmful in JavaScript #7

Open infinnie opened 7 years ago

infinnie commented 7 years ago
(function () {
    try {
        throw new Error("test");
    }
    catch (a) {
        var a = 1, b = 1;
    }
    console.log(a); // undefined
    console.log(b); // 1
})();

is equivalent to:

(function () {
    var a, b; // variable declaration
    try {
        throw new Error("test");
    }
    catch (a) {
        a = 1; // a: local block scope
        b = 1; // b: function scope
    }
    console.log(a); // undefined
    console.log(b); // 1
})();

And ES 6 let/const keywords do not really solve that:

(function () {
    {
        let a;
        var a = 1, // assigned the block-scope, `let` a
            b = 1; // assigned to the function-scope b
        // but var is always “hoisted” and function-scoped — or globally scoped if run globally
    }
    console.log(a); // still undefined
    console.log(b); // still 1
})();

And hoisting causes let to throw an error (temporal dead zone) even if there were a variable in the outer scope having the same name:

(function () {
    var a;
    {
        a = 1; // an error is thrown
        let a;
    }
})();

Finally, the variable scope in C# is different from the scope of variables defined by let in JavaScript:

using System.Windows;
using System.Windows.Controls;

namespace WpfApplication3
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            var buttons = new Button[] { button, button_Copy, button_Copy1 };
            var otherButtons = new Button[] { button_Copy2, button_Copy3, button_Copy4 };

            // show all 3’s (different from JavaScript!)
            for (var i = 0; i < 3; i++)
            {
                buttons[i].Click += (a, b) => {
                    MessageBox.Show(i.ToString());
                };
            }

            // show 0, 1 and 2 respectively
            for (var j = 0; j < 3; j++) {
                var k = j;
                otherButtons[j].Click += (a, b) => {
                    MessageBox.Show(k.ToString());
                };
            }
        }
    }
}

Difference from JavaScript:

// logs 0, 1 and 2
for (let i = 0; i < 3; i++) {
    setTimeout(function () {
        console.log(i);
    }, 2333);
}