美文网首页
阮一峰es6第二章读书笔记-let和const命令

阮一峰es6第二章读书笔记-let和const命令

作者: 文仔CXKSNLXX | 来源:发表于2019-03-03 23:45 被阅读0次

    1. let命令

    基本用法

    • 作用:用来声明变量

    • 与var区别:let声明的变量的有效范围是let命令所在的代码块,而var声明的变量是全局范围

    • 例子 :

      {
        let a = 10;
        var b = 1;
      }
      
      a // ReferenceError: a is not defined.
      b // 1
      
    • 一般可以使用在for循环中,如for(let i = 0;i<10;i++)

    • for循环的一个特别之处,设置循环变量的部分是父作用域,而循环体内容是一个单独的子作用域

    • 例子

      for (let i = 0; i < 3; i++) {
        let i = 'abc';
        console.log(i);
      }
      // abc
      // abc
      // abc
      

    不存在变量提升

    • let命令声明的变量不存在变量提升,而var命令声明的变量则会有变量提升,什么是变量提升呢,就是变量在声明之前就可以使用,但是值为undefined。

    • 例子

      // var 的情况
      console.log(foo); // 输出undefined
      var foo = 2;
      
      // let 的情况
      console.log(bar); // 报错ReferenceError
      let bar = 2;
      

    暂时性死区

    • 意思就是一变量在某个区域内用let声明,那么在该区域内,任何在let声明该变量之前调用这个变量都会报ReferenceError错误

    • 例子

      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(); // 报错
      

      之所以报错,是因为x=y执行的时候,y还没有声明,所以把报错

    • 暂时性死区的本质:只要一进入当前作用域,所要使用的变量就已经存在,但是不可获取,必须等到明确声明变量的一行代码出现,才可以获取和使用该变量

    不允许重复声明

    • let不允许在相同的作用域内,重复声明一个变量,因此不能在函数内部重新声明函数的参数,除非你在函数内部的再加一个子作用域,就可以在自作用域内声明与参数同名的变量。

    块级作用域

    为什么需要块级作用域

    • 只有全局作用域和函数作用域会造成:①内层变量可能会覆盖外层变量 ②用来计数的循环变量泄露为全局变量

      • 对于第一种 例子:
      var tmp = new Date();
      
      function f() {
        console.log(tmp);
        if (false) {
          var tmp = 'hello world';
        }
      }
      
      f(); // undefined
      

      内层if语句的tmp覆盖了外层时间的tmp

      • 对于第二种 例子
       var s = 'hello';
      
      for (var i = 0; i < s.length; i++) {
        console.log(s[i]);
      }
      
      console.log(i); // 5
      

      i变成了全局变量

    ES6的块级作用域

    • let创造了块级作用域,使得外层作用域无法读取内层作用域的变量,并且内层作用域可以定义外层作用域的同名变量。

      • 例子
       function f1() {
        let n = 5;
        if (true) {
          let n = 10;
        }
        console.log(n); // 5
      }
      

      这个例子,如果都是用var的话,n就会编程全局变量,结果为10

    块级作用域与函数声明

    • ES6规定,函数可以在块级作用域中声明,并且块级作用域外不能调用该函数。
    • 浏览器实现
      • 允许在块级作用域内声明函数
      • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部
      • 同时,函数声明还会提升到所在的块级作用域的头部
    • 其他地方则把块级作用域的函数声明当做let处理
    • 最佳实践:由于韩静导致行为差异太大,所以应该避免在块级作用域内声明函数,如果确实需要,那么携程函数表达式形式
    • 其他注意事项:ES6 的块级作用域允许声明函数的规则,只在大括号的情况下成立,所以if后面一定要加括号,即使后面只有一句话。

    const 命令

    • 作用:声明一个只读的常量。一旦声明,常量的值就不能改变

    • const声明的变量一旦声明就必须马上初始化,不能以后赋值,否则会报错

      const foo;
      // SyntaxError: Missing initializer in const declaration
      
    • const与let类似只在声明所在的块级作用域内有效,同样存在暂时性死去,只能在声明的位置之后使用,同样不能重复声明。

    本质

    • const实际上保证不是说变量的值不能改动,而是变量指向的那个内存地址所保存的数据不得改动,那么对于简单的数据类型(数值,字符串,布尔值)来说,它们的值就保存在变量所指的地址,因此等同于变量,但是对于函数或数组来说,变量指向的内存地址,保存的知识一个指向实际数据的指针,const只能保证这个指针是固定的,(即总是执行另一个固定的地址),至于它指向的数据结构就可以变化了。例子

      const foo = {};
      
      // 为 foo 添加一个属性,可以成功
      foo.prop = 123;
      foo.prop // 123
      
      // 将 foo 指向另一个对象,就会报错
      foo = {}; // TypeError: "foo" is read-only
      

      简单来说,就是const只能保证变量是指向这个对象或这个数组,这点是不能变化的,但是对象或数据里面的内容则不能管理到。

    Object.freeze方法

    • 作用:将对象冻结,使之不能添加新的属性

    • 例子

       const foo = Object.freeze({});
      
      // 常规模式时,下面一行不起作用;
      // 严格模式时,该行会报错
      foo.prop = 123;
      

    ES6声明变量的六种方法

    六种方法分别是:var function let const import class

    顶层对象的属性

    • 顶层对象,浏览器中指window对象,node中指global对象,ES5中顶层对象的属性与全局属性是等价的 例子:

      window.a = 1;
      a // 1
      
      a = 2;
      window.a // 2
      
    • 顶层对象与全局变量等价造成的问题:①没法在编译时就爆出变量未声明的错误②程序员很容易不知不觉就创建了全局变量③顶层对象的属性到处可以读写,不利于模块化编程。

    • ES6将全局变量逐步与顶层对象的属性脱钩:表现在varfunction命令声明的全局变量依旧是顶层对象属性,但let命令,const命令、class命令声明的全局变量不属于顶层属性。例子

      var a = 1;
      // 如果在 Node 的 REPL 环境,可以写成 global.a
      // 或者采用通用方法,写成 this.a
      window.a // 1
      
      let b = 1;
      window.b // undefined
      

    global对象

    global是ES5的顶层对象,但在各种实现里面不统一。

    • 浏览器里面,顶层对象是window,但Node和Web Worker没有window。

    • 浏览器和Web Worker里面,self也指向顶层独享,但是Node没有self

    • node里面,顶层对象是golbal,但其他环境不支持
      而为了一段代码能在各种环境都能取到顶层对象,一般用this变量,但是有它的局限性

    • 全局环境中,this会返回顶层对象,但是,node模块和es6模块中,thils返回的是当前模块

    • 函数里面的this,如果不是作为对象的方法运行,而是单纯作为对象运行,this会指向顶层对象,但是,严格模式下,这时this会返回undefined。

    • 不管是严格模式,还是普通模式,new Function(‘return’)()总是会返回全局对象。
      因此很闹找到一种方法在所有情况下,都取到顶层对象,下面是两种勉强可以使用的方法。

      // 方法一
      (typeof window !== 'undefined'
         ? window
         : (typeof process === 'object' &&
            typeof require === 'function' &&
            typeof global === 'object')
           ? global
           : this);
      
      // 方法二
      var getGlobal = function () {
        if (typeof self !== 'undefined') { return self; }
        if (typeof window !== 'undefined') { return window; }
        if (typeof global !== 'undefined') { return global; }
        throw new Error('unable to locate global object');
      };
      

    参考资料

    阮一峰的es6教程

    相关文章

      网友评论

          本文标题:阮一峰es6第二章读书笔记-let和const命令

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