• 深入理解ES6


    知识点

    var 声明变量:
    1、存在变量提升,实际上var无论在哪里声明,都会被当做当前的作用域顶部声明变量。
    2、可以重复声明,后声明的变量会覆盖前声明的变量。
    
    let 声明变量:
    1、不存在变量提升。
    2、禁止重复声明。
    3、块级作用域,只在当前作用域块有用。
    4、临时死区,而且不能在声明之前访问它。
    
    const声明常量:
    1、const 声明的是常量,其值一旦确定后不可以修改
    2、const 声明常量时候必须要进行赋值
    3、const 不存在变量提升,一旦执行快外就会立即销毁。
    4、const 只能在当前代码块级有效,
    5、const 不能重复声明相同常量。
    6、const声明不允许修改绑定,但允许修改值,也就是说用const创建对象后,可以修改该对象的属性值。
    

    一、声明JavaScript的变量有哪些?

    每种编程语言都有变量,声明变量的方法各不同,在JavaScript里面,最经典的var声明一个变量,当ECMAScript6出现后,新增了2个声明变量的方法:let和const,那何时创建变量,用什么声明变量方法会更好呢?

    二、先谈谈var声明及变量提示(hoisting)机制

    var声明一个变量时候,只需要 var name; 或者声明赋值var name = "Bob";

    实际上var无论在哪里声明,都会被当做当前的作用域顶部声明变量。

    (1)什么是变量提示机制?
    // var 的变量提升机制
    function getValue(condition) {
        if (condition) {
            var values = 'Bob';
            return values;
    
        } else {
            console.log(values); // 这里访问到values 是undefined,原因下面解释:
            return null;
            
        }
    }
    
    
    // 原因解释:为什么上面的代码else还能访问values的值,虽然是undefined
    // 无论变量values都会被创建,在编译过程中,JavaScript引擎会将上面的getValue函数修改成这样:
    function getValue(condition) {
    
        // 重点看这里,变量values的声明被提升到函数顶部
        var values;
    
        if (condition) {
            values = 'Bob';
            return values;
    
        } else {
            console.log(values); // 所以这里访问到是声明过的但未赋值的values,所以是undefined。
            return null;
            
        }
    }
    

    三、块级声明的出现

    块级声明用于声明在指定的块的作用域之外无法访问的变量

    • 函数内部
    • 块级中(字符{ }之间的区域)

    四、let声明

    let声明变量和var声明变量,但let有自己的四个特征:

    • 块级作用域,限制在当前的块级作用域中,外面作用域无法访问。
    • 不存在变量提升。
    • 临时死区,而且不能在声明之前访问它。
    • 禁止重复声明相同的变量,否则报错。

    我们可以把刚才聊到的getValue函数修改一下:

    // let 块级作用域 && 不存在变量提升
    function getValue(condition) {
        if (condition) {
    
            // 使用let声明变量
            let values = 'Bob';
            return values;
    
        } else {
            console.log(values); // 这里报错: ReferenceError: values is not defined..
            // 原因就是用let声明的变量,是不存在变量提升的,
            // 而且values变量只能在if{ 这个作用块里面有效 } 外面是访问不到的
            // 同时,在外面访问不仅会访问不到,而且会报错
    
            return null;
    
        }
    }
    
    
    // let 禁止重复声明相同变量
    function getValue() {
        var values = "Bob";
        let values = {name: 'Bob'};
        
        // 使用let声明变量禁止重复声明已经有的变量名
        // 否则报错:SyntaxError: Identifier 'values' has already been declared
    }
    

    五、const声明

    • const 声明的是常量,其值一旦确定后不可以修改。
    • const 声明常量时候必须要进行赋值。
    • const 不存在变量提升,一旦执行快外就会立即销毁。
    • const 只能在当前代码块级有效,
    • const 不能重复声明相同常量。
    • const声明不允许修改绑定,但允许修改值,也就是说用const创建对象后,可以修改该对象的属性值。
    function getValue() {
        // 声明一个常量
        const USER_NAME = "梁凤波";
    
        // 禁止重复声明相同常量,否则报错:TypeError: Assignment to constant variable.
        // const USER_NAME = "Bob";
        
        // 记住:const声明不允许修改绑定,但允许修改值,
        // 也就是说用const创建对象后,可以修改该对象的属性值
        const STUDYENT = {
            name: '梁凤波'
        };
    
        console.log(`STUDYENT.name =  ${STUDYENT.name}`); // STUDYENT.name =  梁凤波
    
        STUDYENT.name = 'Bob';
        console.log(`STUDYENT.name =  ${STUDYENT.name}`); // STUDYENT.name =  Bob
    }
    

    拓展:循环中的块级作用域绑定

    访问for循环后的结果
    // 在for循环内用var 声明,在外面访问到的是for循环后的结果
    for (var i = 0; i < 10; i++) {
    }
    console.log(`i = ${i}`); // i = 10
    
    // 在for循环内用let 声明,在外面 访问不到,块级作用域问题
    for (let i = 0; i < 10; i++) {
    }
    console.log(`i = ${i}`); // ReferenceError: i is not defined
    
    循环中的var声明
    // 经过for循环后,在外面访问i,是直接访问到了结果i = 10
    
    let funcs = [];
    for (var i = 0; i < 10; i++) {
        funcs.push(function () {
            console.log(i);
        })
    }
    
    funcs.forEach(func => {
        func() // 分别输出10次10
    });
    

    原因:循环里每次迭代同时共享着变量i,循环内部创建的函数全保留相同变量的引用,循环结束时候i的值变为10,所以每次调用console.log(i)时候回输出数字10

    为了解决这个问题,可以在循环中使用立即调用函数表达式(IIFE),以强制生成计数器变量的副本:

    使用var达到理想状态
    // 如果要理想效果,在外面分别输出 0 ~ 9,
    // 可以使用闭包暴露出去
    let funcs = [];
    for (var i = 0; i < 10; i++) {
        funcs.push((function (val) {
            return function () {
                console.log(val);
            }
        }(i)))
    }
    
    funcs.forEach(func => {
        func()
    });
    
    循环中的let声明
    let funcs = [];
    for (let i = 0; i < 10; i++) {
        funcs.push(function () {
            console.log(i);
        })
    }
    
    funcs.forEach(func => {
        func() // 分别输出 0 ~ 9
    });
    

    let 声明模仿上述示例IIFE所做的一切简化循环过程,每次迭代循环都会创建一个新变量,并以之前迭代中同名变量的值将其初始化。

    循环中的const声明
    let funcs = [];
    let obj = {
        a: true,
        b: true,
        c: true
    }
    
    for (const key in obj) {
        funcs.push(function () {
            console.log(key);
        })
    }
    
    funcs.forEach(func => {
        func() // 分别输出 a, b, c Authorization
    });
    

    let和const声明循环,const循环是不能改变key的值,const 循环应该使用for-in,for-of,其他和let示例一样,因为每次迭代不会像var循环例子一样修改已有的绑定,而是会创建一个新绑定。

    全局块级作用域绑定

    var RegExp = "Bob";
    
    // 即使是全局对象RegExp定义在window,也不能幸免被var声明覆盖
    console.log(RegExp); // Bob
    console.log(window.RegExp); // Bob
    
    let RegExp = "Bob";
    
    // 用let或const声明不能覆盖全局变量,而只能屏蔽它
    console.log(RegExp); // Bob
    console.log(window.RegExp); // undefined
    console.log(window.RegExp === RegExp); // false
    
    const ncz = 'Hi!'
    console.log('ncz' in window); // false
    

    最后聊一聊块级绑定的最佳实践

    默认使用const,只在确实需求改变变量的值使用let,这样就可以在某种程度上实现代码的不可变,从而防止默写错误产生。

  • 相关阅读:
    Android入门之旅1—ubuntu11.04上搭建And​roid SDK开发环境
    Android入门之旅3—ubuntu11.4上通过adb连接M9手机
    HTML页面的控件的显示与隐藏
    Javascript所属document对象使用细说(转载)
    php备份和恢复mysql数据库
    VB.net 代码 调用外部Ping命令判断网络连通状况
    面向对象技术第一讲 多态性
    无法在Web服务器上启动调试。未将项目配置为进行调试
    (PHP,mysql)Fatal error: Call to undefined function mysql_connect() 解决方案
    left join inner 使用细节
  • 原文地址:https://www.cnblogs.com/liangfengbo/p/9096490.html
Copyright © 2020-2023  润新知