重温ES6之let和const

本文详细介绍了ES6中let和const的引入如何改变了JavaScript的变量声明。var存在的变量提升、作用域污染等问题在let和const中得到解决。let声明的变量不会提升,不允许重复声明,而const则进一步确保了常量的不可变性。此外,文章通过实例解释了在循环中使用var、let和const的差异,以及它们在全局作用域中的表现。
摘要由CSDN通过智能技术生成


前话

  • 2015年,终于迎来了ECMScript标准的第6版,简称ES6
  • ES5还要追溯到2009年
  • 虽然ES6出现了,但是各大浏览器厂商还并不完美支持ES6,于是便出现了一大批JS编译器(如Babel,Traceur等)
  • 这些编译器可以将ES6和ES6+的代码转换成当前浏览器或环境兼容的JS代码

let和const的出现带来的变化

  • 在ES6之前:
    • 1.声明变量的关键字只有var
    • 2.没有块级作用域
    • 3.只有函数作用域和全局作用域
  • 出现ES6之后:
    • 1.引入了let和const两个关键字
    • 2.let和const既可以声明变量,还可以将变量绑定到当前所处的任意作用域中,就是把变量的作用域封闭在所处的代码块(即用花括号字符“{”和“}”之间的区域)。例如if语句

【let和const】 与 var 之间的不同

  • 1.不允许声明提升
  • 2.不允许重复声明
  • 3.不覆盖全局变量

var详解

var声明的变量会挂载到全局上,因此会污染全局变量,并且没有作用域

// 浏览器的控制台测试
var a = 1 
console.log(window.a) // 1 

{
    var b = 1
}
console.log(window.b)  // 1
console.log(b)  // 1

会导致变量提升,这里补充一下,函数也会导致变量提升

console.log(a)  // undefined
var a = 1

可以被重复声明,后来声明的值会覆盖掉之前声明的值

var a = 1
var a = 2
var a = 3
console.log(a) // 3 

let详解

let声明的变量,其声明语句不会再被提升

// var声明的是没有块作用域的,所以输出 undefined
console.log(outer) // undefined

{
    // 由于outer有变量提升,所以输出 undefined
    console.log(outer) // undefined
    var outer = true
    console.log(outer) // true
}

console.log(outer)  // true
// 会报错: inner is not defined
// console.log(inner) 

{
    // 会报错: Cannot access 'inner' before initialization
    // console.log(inner)

    // 使用let声明的,不能被提升到代码块外部,因此它的作用域只限于当前代码块内
    // 此时变量处于【临时死区(TDZ)】
    // 使用let或者const声明的变量在声明之前会被放到TDZ中,若访问这些变量就会触发运行时错误
    let inner = true

    console.log(inner)
}

// console.log(inner)
  • 我们可以将下面的代码转为 es5 ,看看编译成es5后到底是怎么样的
let a = 100; 
{
    console.log(a) // 报错,这里涉及到一个概念。即【暂时性死区”(temporal dead zone,简称 TDZ)】,其意思就是只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
    // 下方使用了let声明,即 a 已经被绑定在该作用域了,上面打印时候发现当前的作用域有 a,那么也就不会往外层作用域找,并且使用let声明的变量不会导致变量提升,因此就报错了。
    let a = 1
}

let不允许重复声明

  • 注意:对于这一特性,有一个前置条件,那就是只有在相同的作用域时,才不允许同一个变量重复声明
var duplicate
let repeat

var duplicate

// 报错:Identifier 'repeat' has already been declared
// let repeat  

{
    // 属于不同的作用域,因此可以正常声明
    let repeat
}

let在全局作用域中的特性

  • 当var在全局作用域中声明变量的时候,该变量会成为全局变量及全局对象(如浏览器中的window对象)的一个属性,这样不利于代码的模块化
  • 并且使用var声明的新变量有可能会覆盖全局对象中已存在的属性
  • 于是,ES6就规定用let可将全局变量和全局对象断开联系
var global = true
console.log(window.global)  // 输出: true

let whole = true
console.log(window.whole)  // 输出:undefined
var Math = true
console.log(window.Math)  // 输出:true

let Math = true
console.log(window.Math)  // 输出:Math对象

const详解

const同时也拥有上述let的 3 个特性

  • 1.声明的变量,其声明语句不会再被提升
  • 2.let不允许重复声明
  • 3.在全局作用域中的特性

const可以声明一个常量

  • 注意:const与let不同,在声明时必须初始化,即赋值
// 报错: Missing initializer in const declaration
// const number;


// const digit = 10;
// 报错:Assignment to constant variable.
// digit = 20
  • 强调:const限制的其实是变量与内存地址之间的绑定,即const让变量无法更改所对应的内存地址
  • 如果是基本数据类型,那么对应的内存地址保存的就是值
  • 如果是引用类型,那么对应的内存地址保存的就是指向实际数据的一个指针
  • 当用const声明的变量,其值是对象的时候,那么可以修改对象中的属性和方法
const obj = {}
obj.name = 'zsy'
obj.age = function () {
    return 21
}

循环中的var

立即执行函数表达式(IIFE)解决循环中的异步回调问题

for (let i = 0; i < 3; i++) {
    (function (n) {
        setTimeout(function () {
            console.log(n)
        }, 0);
    })(i)
}
// 输出:0 1 2 

循环中的let

  • ES6规定了let声明在循环内部的行为
for (let i = 0; i < 3; i++) {
    setTimeout(function () {
        console.log(i)
    }, 0);
}
// 输出:0 1 2 
  • 上述的代码中并没有出现循环中的异步回调问题
  • 因为在每次循环的时候,都会重新创建一个叫做 i 的同名变量,并且将其初始化为计算后的值
  • 而循环体内调用的 i 变量不会受其他同名变量的影响

循环中的const

  • const 声明在循环内部的行为与let声明类似
  • 但是由于const声明的变量,其值无法修改
  • 因此若重新赋值,比如执行增量操作时,就会抛出异常
let author = {
    name: 'zsy',
    age: 29
}
for (const key in author) {
    console.log(key)  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值