2.let 和 const

let 命令

块级作用域中的声明

for循环中的使用

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () { //这一行的i定义函数的时候绑定的,和var,let无关,不影响
    console.log(i); //这一行的i是执行的时候才计算的,用var就只能找到10了
  };
}
a[6](); // 6
//函数执行时的值是要去定义的时候找的,var的i是全局的,只能有一个,所以会被覆盖
//let的i是每次重新声明的,每个{}中都有一个,有10个不同的,所以不会互相影响

如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?

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

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

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

for (let i = 0; i < 3; i++) {
    i = 'abc';
    console.log(i);
}
// abc 只输出一次

上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。

寻找变量i的值会就近原则,先在自己的作用域找,如果没有再去父作用域找。赋值操作会将’abc’赋值给父作用域的i,然后打印’abc’,然后运行Boolean('abc' < 3)得到false,跳出循环,所以只输出一个abc

Boolean('abc' < 3)的过程是:字符串‘abc’由于不能转换成合理的数值,会被转换为NaN,而任何操作数与 NaN 进行 关系比较,结果都是 false

let命令不存在变量提升

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

暂时性死区

  • 如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
  • 在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

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

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

在作用域内,在let声明之前调用let声明的变量都会因为“死区”报错

// 不报错
var x = x;

// 报错
let x = x;
// ReferenceError: x is not defined
  • 暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

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

  • 不能在函数内部重新声明参数。
function func(arg) {
  let arg;
}
func() // 报错

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

块级作用域

  • 内层作用域可以定义外层作用域的同名变量。
  • 内层作用域可以给外层作用域的同名变量赋值。
{
    let a = 5
    {
        let a = 10
    }
    console.log(a); //5
}
{
    let a = 5
    {
        a = 10
    }
    console.log(a); //10
}

ES6规定块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
浏览器实际块级作用域内声明的函数,行为类似于var声明的变量,即会提升到全局作用域或函数作用域的头部,然后给函数名变量名赋值为undefined。

应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

  • ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
  • let只能出现在当前作用域的顶层
// 第一种写法,报错
if (true) let x = 1;

// 第二种写法,不报错
if (true) {
  let x = 1;
}

const 命令

  • 对于const来说,只声明不赋值,就会报错。
  • const只是不改变指针地址,简单数据类型指针直接指向相应的值,复杂数据类型指针指向真实数据的地址,所以const obj = {}中obj的内容可以改变。
  • 如果真的想将对象冻结,应该使用Object.freeze方法。
  • 彻底冻结对象时,应该深度遍历每个属性,对每个属性也进行冻结。

顶层对象

  • var命令和function命令声明的全局变量,是顶层对象的属性
  • let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性
  • 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值