ES6 学习笔记

let 和 const 命令


学习资料:ECMAScript 6 入门

let

  • 所声明的变量,只在let命令所在的代码块内有效。用途:循环计数器。

如果使用var,只有一个全局变量i:

    var a = [];
    for (var i = 0; i < 10; i++) {
            a[i] = function () {
                    console.log(i);
            };
    }
    a[6](); // 10

如果使用let,声明的变量仅在块级作用域内有效,JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算:

    var a = [];
    for (let i = 0; i < 10; i++) {
            a[i] = function () {
                    console.log(i);
            };
    }
    a[6](); // 6

设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域:

    for (let i = 0; i < 3; i++) {
            let i = 'abc';
            console.log(i);
    }
    // abc
    // abc
    // abc
  • 不存在变量提升

let所声明的变量一定要在声明后使用:

    // var 的情况
    console.log(foo); // 输出undefined
    var foo = 2;

    // let 的情况
    console.log(bar); // 报错ReferenceError
    let bar = 2;
  • 暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。所以需要先声明再使用:

    var tmp = 123;

    if (true) {
            tmp = 'abc'; // ReferenceError
            let tmp;
    }

    if (true) {
            // TDZ开始
            tmp = 'abc'; // ReferenceError
             console.log(tmp); // ReferenceError

            let tmp; // TDZ结束
            console.log(tmp); // undefined

            tmp = 123;
            console.log(tmp); // 123
    }

隐蔽的死区:

    function bar(x = y, y = 2) {
            return [x, y];
    }

    bar(); // 报错
  • 不允许重复声明

let不允许在相同作用域内,重复声明同一个变量。

    // 报错
    function func() {
            let a = 10;
            var a = 1;
    }

    // 报错
    function func() {
            let a = 10;
            let a = 1;
    }

    function func(arg) {
            let arg; // 报错
    }

    function func(arg) {
            {
                    let arg; // 不报错
            }
    }

块级作用域

  • ES5中没有块级作用域

ES5中没有块级作用域,内层变量可能会覆盖外层变量:

    var tmp = new Date();

    function f() {
            console.log(tmp);
            if (false) {
                    var tmp = 'hello world';
            }
    }

    f(); // undefined

ES5中没有块级作用域,用来计数的循环变量泄露为全局变量:

    var s = 'hello';

    for (var i = 0; i < s.length; i++) {
            console.log(s[i]);
    }

    console.log(i); // 5
  • ES6 的块级作用域

      function f1() {
              let n = 5;
              if (true) {
                      let n = 10;
              }
              console.log(n); // 5
      }
    
  • 块级作用域与函数声明

ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。但在浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。

    // 浏览器的 ES6 环境
    function f() { console.log('I am outside!'); }

    (function () {
            if (false) {
            // 重复声明一次函数f
            function f() { console.log('I am inside!'); }
            }

            f();
    }());
    // Uncaught TypeError: f is not a function

考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

    // 函数声明语句
    {
            let a = 'secret';
            function f() {
                    return a;
            }
    }

    // 函数表达式
    {
            let a = 'secret';
            let f = function () {
                    return a;
            };
    }

ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。

    // 不报错
    'use strict';
    if (true) {
            function f() {}
    }

    // 报错
    'use strict';
    if (true)
            function f() {}

const 命令

const声明一个只读的常量。一旦声明,常量的值就不能改变。

const一旦声明变量,就必须立即初始化,不能留到以后赋值。

与let类似,只在声明所在的块级作用域内有效。声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。不可重复声明。

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。

如果真的想将对象冻结,应该使用Object.freeze方法。

    const foo = Object.freeze({});

    // 常规模式时,下面一行不起作用;
    // 严格模式时,该行会报错
    foo.prop = 123;

除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。

    var constantize = (obj) => {
            Object.freeze(obj);
            Object.keys(obj).forEach( (key, i) => {
                    if ( typeof obj[key] === 'object' ) {
                            constantize( obj[key] );
                    }
            });
    };

顶层对象的属性

var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。

垫片库system.global可以在所有环境拿到global。

    // CommonJS 的写法
    var global = require('system.global')();

    // ES6 模块的写法
    import getGlobal from 'system.global';
    const global = getGlobal();
原文地址:https://www.cnblogs.com/renleimlj/p/7766006.html