let 和 const 命令

let 命令

所声明的变量只在let命令所在的代码内有效

JavaScript引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算

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

不存在变量提升

它所声明的变量一定在声明后使用, 否则会报错

暂时性死区

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

ES6规定:如果区块中存在let和const命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域。只要在声明之前就使用这些变量,就会报错

总之,在代码块中,使用let命令声明变量之前,该变量都是不可用的,在语法上称为“暂时性死区

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

不存在重复声明

块级作用域

为什么需要块级作用域

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var tmp = new Date();
    function f() {
    console.log(tmp);
    if (false) {
    var tmp = 'hello world'
    }
    }

    f(); // undefined
    // 原因在于变量提升导致内层的tmp变量覆盖了外层的tmp变量
  2. 用来计数的循环变量泄露成为全局变量

1
2
3
4
5
var s = 'hello';
for(var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i);

ES6的块级作用域

  1. 外层作用域无法读取 内层作用域的变量
  2. 内层作用域可以定义外层作用域的同名变量

块级作用域与函数声明

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

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

do表达式

1
2
3
4
lex x = do {
let t = f();
t * t + 1;
}; // 变量x会得到整个块级作用域的返回值

const命令

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

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

  • const的作用域和let相同,只在声明所在块级作用域内有效

  • const声明的常量也不会提升,同样存在暂时性死区,只能在声明后使用

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

    对于简单类型的数据(数值、字符串、布尔值)而言,值就保存在变量指向的内存地址中,因此等同于常量;但对于复合类型的数据(主要是对象和数组)而言,变量指向的内存地址保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变得,完全不能控制

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