美文网首页ES6
Es6 Block Binding

Es6 Block Binding

作者: xiaohesong | 来源:发表于2018-10-15 11:30 被阅读26次

    es5es6的区别里,关于块级绑定是被津津乐道的。之前没有记录,今天就把它记录下来。
    我们知道var会有变量提升
    es6letconst可以避免这个,且会生成块级作用域。

    块级声明

    1. function里面
    2. 块内(由{}字符表示)
    let 声明
    function getValue(condition) {
    
        if (condition) {
            let value = "blue";
    
            // other code
    
            return value;
        } else {
    
            // value 不存在这里
    
            return null;
        }
    
        // value 不存在这里
    }
    
    无重复声明
    var count = 30;
    
    // Syntax error
    let count = 40;
    

    上面会报错,count被声明两次:一次使用var,一次使用let。因为let不会重新定义已存在于同一范围内的标识符,所以let声明将引发错误。

    var count = 30;
    
    // Does not throw an error
    if (condition) {
    
        let count = 40;
    
        // more code
    }
    

    这个不会报错,因为实在新的作用域(块级)创建的新变量。

    The Temporal Dead Zone

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

    这个就是所谓的tdz,TDZ永远不会在ECMAScript规范中明确命名,但该术语通常用于描述为什么letconst声明在声明之前无法访问。

    js引擎查看即将发生的块并找到变量声明时,它会将声明提升到函数顶部或全局范围(对于var),或者将声明放在TDZ中(对于letconst)。

    上面的例子会报错,因为在这个块级作用域内的声明之前存在这个TDZ,但是你可以在块级作用域外使用:

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

    TDZ只是块绑定的一个独特方面。另一个独特的方面与它们在循环内的使用有关。

    block binding in loops

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

    es6之前解决这个问题可以使用IIFE

    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,1,2,...
    });
    

    但是es6之后,可以直接使用let

    var funcs = [];
    
    for (let i = 0; i < 10; i++) {
        funcs.push(function() {
            console.log(i);
        });
    }
    
    funcs.forEach(function(func) {
        func();     // outputs 0, then 1, then 2, up to 9
    })
    

    这个是因为在每次的迭代中,都会创建一个新的变量,这就导致每个创建的内部的方法都有一个自己的变量。每次创建的时候,都会分配值。

    重要的是要理解循环中let声明的行为是规范中特别定义的行为,并不一定与let的非提升特性有关。实际上,let的早期实现没有这种行为,因为它稍后在过程中添加。

    const 和 let

    其实const的行为和let的行为差不多。只是const定义的是常量,不变的数据。let定义的是改变的数据。并且在声明const的时候必须存在值。

    const name; //error
    const name = 'my name' 
    name = 'your name' // error
    let age;
    age = 18;
    

    对于const需要明确一点,就是改变的是什么?看下面这个。

    const person = {
        name: "Nicholas"
    };
    
    // works
    person.name = "Greg";
    
    // throws an error
    person = {
        name: "Greg"
    };
    

    可以更改person.name而不会导致错误,因为这会更改person包含的内容,并且不会更改person绑定的值。当此代码尝试为person分配值(从而尝试更改绑定)时,将引发错误。const如何与对象一起工作的这种微妙之处很容易被误解。请记住:const阻止修改绑定,而不是阻止修改绑定值。

    本文出自

    相关文章

      网友评论

        本文标题:Es6 Block Binding

        本文链接:https://www.haomeiwen.com/subject/ioaxzftx.html