跟着阮神学ES6——变量与做用域

let 命令是什么

let 是一个用来声明变量的命令。它的用法相似于var ,可是所声明的变量,只在let 命令所在的代码块内有效。javascript

let 命令的特性?

  1. 所声明的变量的块内有效性
  2. 无初始化的变量提高
  3. 暂时性死区
  4. 不容许重复声明

变量提高是什么?

JavaScript引擎中,代码会在执行上下文中执行。而在执行上下文的建立阶段,声明的各类类型变量 (var, let, const, function, function*, class) 都会被添加到词法环境中。html

  1. let , const, class 的「建立」过程被提高了,可是「初始化」没有提高。
  2. var 的「建立」过程被提高了,而且会被「初始化」为undefined。
  3. function, function* 的「建立」「初始化」和「赋值」都被提高了。
  4. function, function*提高的优先级别更高,更早被添加到词法环境中。
  5. let, const, class, function, function*被添加到词法环境中,而 var 被添加到变量环境中。
  6. 变量环境也是一个词法环境,只用来存储 var 变量绑定。

特别的for 循环

使用for循环时,发现let居然能够重复定义同名变量:java

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

总结:这代表函数内部的变量i 与for循环变量i 不在同一个做用域。循环变量的那部分是一个父做用域,而循环体内部是一个单独的子做用域。web

为何须要块级做用域?

ES5 只有全局做用域和函数做用域,没有块级做用域,这带来不少不合理的场景。编程

内层变量可能会覆盖外层变量

var tmp = new Date();

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

f(); // undefined
复制代码

用来计数的循环变量泄露为全局变量

var s = 'hello';

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

console.log(i); // 5
复制代码

上面代码中,变量i只用来控制循环,可是循环结束后,它并无消失,泄露成了全局变量。数组

ES6块级做用域特色

  1. ES6 容许块级做用域的任意嵌套浏览器

  2. ES6 的块级做用域必须有大括号markdown

  3. 内层做用域能够定义外层做用域的同名变量数据结构

    {{{{
      let insane = 'Hello World';
      {let insane = 'Hello World'}
    }}}};
    复制代码
  4. 匿名当即执行函数表达式部分功能被替代模块化

    // IIFE 写法
    (function () {
      var tmp = ...;
      ...
    }());
    
    // 块级做用域写法
    {
      let tmp = ...;
      ...
    }
    复制代码
  5. 容许在块级做用域之中声明函数

    ES6 规定,块级做用域之中,函数声明语句的行为相似于let,在块级做用域以外不可引用。

    1. ES5 规定,函数只能在顶层做用域和函数做用域之中声明,不能在块级做用域声明。
    2. 浏览器没有遵照这个规定,为了兼容之前的旧代码,仍是支持在块级做用域之中声明函数,不会报错。
    3. 为减轻所以产生的不兼容问题,ES6 在附录 B里面规定,浏览器能够有本身的行为方式(相似于var)。
    4. 考虑到环境致使的行为差别太大,应避免在块级做用域内声明函数。
    5. 严格模式下,函数只能声明在当前做用域的顶层。

const 命令的特色

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

  2. 只在声明所在的块级做用域内有效(与let命令相同)。

  3. const命令声明的常量也是无初始化提高,一样存在暂时性死区。

  4. const声明的常量,也与let同样不可重复声明。

  5. const仅仅保证指向的内存地址数据不得改动。

    对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,所以等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即老是指向另外一个固定的地址),至于它指向的数据结构则是可变的。

  6. 若是想冻结对象,应该使用Object.freeze方法。

ES6 声明变量的六种方法

  1. var
  2. function
  3. let
  4. const
  5. import
  6. class

var命令和function命令是ES5 中仅有的两种声明变量的方法。letconst命令,import命令和class命令则是ES6新增的声明变量的方法。

全局变量与顶层对象

  1. 顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。
  2. ES5 之中,顶层对象的属性与全局变量是等价的。
  3. ES6 之中, var命令和function命令声明的全局变量,依旧是顶层对象的属性。
  4. ES6 之中, let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。

顶层对象与全局变量等价的缺点?

  1. 无法在编译时就报出变量未声明的错误
  2. 容易不知不觉地就建立了全局变量
  3. 顶层对象的属性是处处能够读写的,这很是不利于模块化编程
  4. 顶层对象是一个有实体含义的对象(window指浏览器的窗口对象),含义混淆。

ES2020为何新增globalThis对象?

JavaScript 语言存在一个顶层对象,它提供全局环境(即全局做用域),全部代码都是在这个环境中运行。可是,顶层对象在各类实现里面是不统一的。

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

  • 浏览器和 Web Worker 里面,self也指向顶层对象,可是 Node 没有self

  • Node 里面,顶层对象是global,但其余环境都不支持。

相关文章
相关标签/搜索