重学红宝书,再走长征路!🚀🚀🚀var、let、const的区别

1,217 阅读4分钟

基础好是你的谎言

好久之前读完了两遍红宝书第三版,所以一直洋洋得意自己基础好,

new ducument.jpg

但是经过这次的字节抖音面试,真的体会到了什么是基础不好,我盲目的自信像极了人类面对三体水滴飞船时,坚信这是三体人送来的礼物一样愚蠢。

毁灭你与你何干!

痛定思痛,打算重新读一遍红宝书(第四版),并且将每天的阅读笔记记录下来,所以这是重走长征路系列的第一篇。期待我后面输出的同学可以关注一波~

文章同步在公众号:萌萌哒草头将军

letvar 的区别

函数作用域,可以冗余声明,变量提升

块级作用域,无法荣冗余声明,没有变量提升,但是有暂时性死区

作用域的区别

块级作用域仅仅在代码块里起作用,例如:

if (true) {
    let age = 10;
    console.log(age) // 10
}
console.log(age) // 语法错误

但是换做var则可以访问。

if (true) {
    var age = 10;
    console.log(age) // 10
}
console.log(age) // 10

函数作用域仅仅在函数内部起作用,函数外部无法访问,如果换做let也无法访问,因为函数也是个代码块。

function add () {
    var age = 10
}
console.log(age) // 语法错误

变量提升暂时性死区

变量提升:指变量声明之前可以访问变量的行为

console.log(name) // undefined
var name = "mmdctjj"

暂时性死区:变量声明之前无法访问的行为

onsole.log(name) // 语法错误
let name = "mmdctjj"

冗余声明

可以冗余声明的情况

var name = "萌萌哒草头将军"
var name = "mmdctjj"

无法冗余声明

let name = "萌萌哒草头将军"
let name = "mmdctjj" // 语法错误:name已经声明了

而且这种报错不会因为混用受影响

var name = "萌萌哒草头将军"
let name = "mmdctjj" // 语法错误:name已经声明了
let name = "萌萌哒草头将军"
var name = "mmdctjj" // 语法错误:name已经声明了

但是在不同代码块之间可以重复声明

// 仅做代码演示,不建议这么声明变量
if (local === "zn-Ch") {
    let name = "萌萌哒草头将军"
} else {
    let name = "mmdctjj"
}

全局声明的一些差异

var会将变量挂载到window对象上

var name = "mmdctjj"
window.name === name // true

但是let则不会

let name = "mmdctjj"
window.name // undefined

另外,如果省略声明变量的关键字,那么默认会使用var声明,也就是说

people = "a"
window.people === people // true

局部声明的一些差异

在函数中使用var声明一个变量,在执行函数后,该变量会保存在window对象上

function test() {
    myName = "mmdctjj"
}
test()
myName // "mmdctjj"
window.myName // "mmdctjj"

let依然不会。造成这种差异的原因:变量提升

for循环中的一些差异

var在循环时会将变量溢出到外部

for (var i = 0; i < 5; i ++) {}
console.log(i) // 5

let则不会

for (let i = 0; i < 5; i ++) {}
console.log(i) // 语法错误:i未定义

另外会导致超出预期的行为

for (var i = 0; i < 5; i ++) {
    setTimeout(() => console.log(i), 0)
}
// 预期:0,1,2,3,4
// 实际:5,5,5,5,5
```可能
但是`let`不会
```js
for (let i = 0; i < 5; i ++) {
    setTimeout(() => console.log(i), 0)
}
// 实际:0,1,2,3,4

const 使用

基本的使用差异

constlet十分相似,不同的是,const声明变量时必须对值进行初始化赋值,且值无法被修改。

const name; // 语法错误: Missing initializer in const declaration
const people = "mmdctjj"
const people = "萌萌哒草头将军" // 语法错误
const age = 18
people = "萌萌哒草头将军" // 语法错误
age = 19 // 语法错误

我们知道变量保存基本变量类型时,只保存值,所以当用const声明一个基本类型,意味着无法被修改。

如果值为引用类型,也不能修改变量的引用地址。所以下面的修改都会报错

const people = {}
people = {} // 语法错误

但是当值为引用类型时,我们可以修改引用类型内部的属性

const people = {
    name: "mmdctjj";
}
people.name = "萌萌哒草头将军";

无法在修改值的for循环中使用

for (const i = 0; i < 5; i ++) {}
// TypeError: Assignment to constant variable.

但是如果不修改值的情况,则可以使用

let i = 5
for (const j = 7; i < 5; i ++) {
    console.log(j)
}
// 7, 7, 7, 7, 7

这是因为迭代变量会自增。

for 循环中,迭代变量通常是一个数字计数器,通过自增操作来访问下一个元素。而在其他循环结构(如 for...offorEach)中,迭代变量会自动获得下一个元素,无需显式自增。

可以在for of for in中使用

for (let key in {a: 1, b: 2}) {
    console.log(key)
}
// "a", "b"
for (let value of [1, 2]) {
    console.log(value)
}
// 1, 2

这是因为for of for in会为每个变量声明新的变量,而不是重新赋值。

使用风格推荐

能不用var就不用var,能用const就用const,不需要修改的常量使用const,需要修改的变量使用let

最后

文章很多细节都是来自于红宝书,一些地方可能加入自己的理解,希望不会带来误解,有错误地方欢迎指正。

想要一起学习的小伙伴可以看这里