• 深入理解ES6读书笔记1:块级绑定


    var 声明与变量提升

    使用 var 关键字声明的变量,无论其实际声明位置在何处,都会被视为声明于所在函数的顶部(如果声明不在任意函数内,则视为在全局作用域的顶部)。这就是变量提升,不过变量的声明虽然被提升到了顶部,但初始化工作还保留在原处。

    function getValue(condition) {
        if (condition) {
            var value = "blue";
            // 其他代码
            return value;
        } else {
            // value 在此处可访问,值为 undefined
            return null;
        }
        // value 在此处可访问,值为 undefined
    }

    块级声明

    块级声明让所声明的变量在指定块的作用域外无法被访问。
    块级作用域在如下情况被创建:
    1. 在一个函数内部
    2. 在一个代码块(由一对花括号包裹)内部

    let声明

    let 声明的语法与 var 的语法一致,但会将变量的作用域限制在当前代码块中,并且不会被提升到当前代码块的顶部。

    function getValue(condition) {
        if (condition) {
            let value = "blue";
            // 其他代码
            return value;
        } else {
            // value 在此处不可用
            return null;
        }
        // value 在此处不可用
    }

    禁止重复声明

    如果一个标识符已经在代码块内部被定义,那么在此代码块内使用同一个标识符进行 let 声明就会导致抛出错误。例如:

    var count = 30;
    // 语法错误
    let count = 40;
    但是在嵌套的作用域内使用 let 声明一个同名的新变量,则不会抛出错误
    var count = 30;
    // 不会抛出错误
    if (condition) {
        let count = 40;
        // 其他代码
    }

    常量声明

    使用 const 声明的变量会被认为是常量,它们的值在被设置完成后就不能再被改变。
    正因为如此,所有的 const 变量都需要在声明时进行初始化。
    常量声明与 let 声明一样都是块级声明,在声明它们的语句块外部无法访问,并且声明也不会被提升。
    const 声明在同一作用域(全局或是函数作用域)内定义一个已有变量时也会和let一样抛出错误。
    如果 const 声明的是对象,阻止的是对绑定值的修改,不会阻止对成员值的修改。

    const person = {
        name: "Nicholas"
    };
    // 正常
    person.name = "Greg";
    // 抛出错误
    person = {
        name: "Greg"
    };

    暂时性死区

    使用 let 或 const 声明的变量,在达到声明处之前都是无法访问的,试图访问会导致一个引用错误,即使在通常是安全的操作时(例如使用 typeof 运算符)。

    if (condition) {
        console.log(typeof value); // 引用错误
        let value = "blue";
    }

    JS 引擎检视接下来的代码块并发现变量声明时,它会在面对 var 的情况下将声明提升到
    函数或全局作用域的顶部,而面对 let 或 const 时会将声明放在暂时性死区(temporal dead zone,TDZ )内。任何在暂时性死区内访问变量的企图都会导致运行时错误。
    然而,可以在变量被定义的代码块之外对该变量使用 typeof。

    console.log(typeof value); // "undefined"
    if (condition) {
        let value = "blue";
    }

    当 typeof 运算符被使用时, value 并没有在暂时性死区内,因为这发生在定义 value 变量的代码块外部。

    循环中的块级绑定
    下面例子用var 声明导致变量提升,结果i为10。

    for (var i = 0; i < 10; i++) {
    }
    console.log(i);//10

    如果把var改成let,则会抛出错误。

    for (var i = 0; i < 10; i++) {
    }
    console.log(i);//抛出错误:i is not defined。

    因为let定义的变量i仅在for循环内部可用。

    循环内的函数

    var funcs = [];
    for (var i = 0; i < 10; i++) {
        funcs.push(function() {
            console.log(i);
        });
    }
    funcs.forEach(function(func) {
        func(); // 输出数值 "10" 十次
    });

    因为变量 i 在循环的每次迭代中都被共享了,意味着循环内创建的那些函数都拥有对于同一变量的引用。
    修正这个问题,在循环内使用立即调用函数表达式(IIFEs),以便在每次迭代中强制创建变量的一个新副本:

    var funcs = [];
    for (var i = 0; i < 10; i++) {
        funcs.push((function(value) {
            return function() {
                console.log(value);
            }
        } (i)));
    }
    funcs.forEach(function(func) {
        func(); // 从 0 到 9 依次输出
    });

    变量 i 被传递给 IIFE,从而创建了 value 变量作为自身副本并将值存储于其中。
    使用 let 与 const 的块级绑定可以简化这个循环

    var funcs = [];
    for (let i = 0; i < 10; i++) {
        funcs.push(function() {
            console.log(i);
        });
    }
    funcs.forEach(function(func) {
        func(); // 从 0 到 9 依次输出
    })

    在循环中let 声明每次都创建了一个新的 i 变量,因此在循环内部创建的函数获得了各自的 i 副本。
    如果上面let改成const,则会在一次迭代后因为试图改变i的值而抛出错误。
    let这种方式在 for-in和 for-of 循环中同样适用:

    var funcs = [],
    object = {
        a: true,
        b: true,
        c: true
    };
    for (let key in object) { //let可以改成const
        funcs.push(function() {
            console.log(key);
        });
    }
    funcs.forEach(function(func) {
        func(); // 依次输出 "a"、 "b"、 "c"
    });

    const不能用于常规for循环,但可以用于for-in 和 for-of,因为循环为每次迭代创建了一个新的变量绑定,而不是试图去修改已绑定的变量的值。

    块级绑定新的最佳实践

    因为大部分变量在初始化之后都不应当被修改,所以在默认情况下使用 const 、并且只在知道变量值需要被更改的情况下才使用 let 。

  • 相关阅读:
    Web大前端面试题-Day12
    Web大前端面试题-Day11
    每天刷Web面试题(前10天汇总)
    Web大前端面试题-Day10
    Web大前端面试题-Day9
    Web大前端面试题-Day8
    Web大前端面试题-Day5
    Web大前端面试题-Day7
    Web大前端面试题-Day6
    php获取时间是星期几
  • 原文地址:https://www.cnblogs.com/gdjlc/p/14512941.html
Copyright © 2020-2023  润新知