一文了解let、const与var的区别

之前遇到过一位后端大哥自告奋勇,参与前端一个vue3项目的功能实现。当功能完成时大哥体现出他对vue3框架正确的认知,但轮到我看代码时,满屏的var让我不禁汗颜。

“声明变量不就是用var吗

“let和var不都是声明变量你直接把var替换成let不就行了......

相信不只是这位大哥,也有不少同学在学习ES6的知识后,也是简单认为let和const就只是代替了var的新用法。

变量提升

ES6之前我们只学了var关键字进行变量的声明,同时我们可以复习下变量提升的概念。

var声明的变量具有变量提升的特性,在javascript的创建阶段过程中,会对声明的变量与函数进行收集,提升到作用域的顶部。

其中有两个细节:

1.只有声明被提升(变量会初始化为undefined)

2.当变量名和函数名冲突时,函数会被优先提升

具体看下变量提升的效果:

console.log(num) // undefined

console.log(fun) // function fun(){...}

var num = 1

var fun = 2

function fun(){

// ...

}

console.log(num) // 1

console.log(fun) // 2

一、let、const

1.let和const的具体使用

ES6新增了letconst关键字:

  1. let用于声明变量,用法与var类似

  2. const用于声明常量:

    1. 与变量不同,常量是一个恒定的值,只读,不可修改

    2. 常量在定义时必须进行初始化赋值

  3. 相同特性:

    1. 在相同作用域内,无法对同一个变量/常量进行重复声明

    2. 存在暂时性死区

    3. 会形成块级作用域

    4. 不会在全局声明时(在最顶层作用域)创建window对象的属性

我们通过代码,观察以上的特性:

  • const声明的常量无法被修改。

let varData = 'variable';
const constData = 'constant';
varData = 1;
constData = true // Uncaught TypeError: Assignment to constant variable.

  • const声明时必须进行初始化(let可以不进行初始化赋值)。

let varData;
const constData; // Uncaught SyntaxError: Missing initializer in const declaration

  • const声明的注意点:

const只是限制变量绑定的值,不会限制引用数据类型内部的变动。

const a = {
num : 1
}
a.num = 2 // 对象的属性仍然可以被改动,不被影响
a = 2 // 报错

  • 同一作用域内,无法对同一个变量/常量进行重复声明。

let varData;
let varData = true; // Uncaught SyntaxError: Identifier 'varData' has already been declared

const constData = 1;
const constData = 2 //Uncaught SyntaxError: Identifier 'constData' has already been declared

var varData
let varData = 2 //Uncaught SyntaxError: Identifier 'varData' has already been declared

  • 重复声明的注意点:

在switch语句中,因为let或const声明会形成块级作用域,也会导致重复声明。switch (key) {
case 1:
let a = 1
break;
case 2:
let a = 2 //Identifier 'a' has already been declared
break;
}

2.暂时性死区

暂时性死区:Temporal dead zone——TDZ

先看一段代码,方便我们对暂时性死区的理解:

console.log(a) // undefined

var a = 1

在js阶段时,我们学过预解析,var声明的变量会在初始化赋值前,进行变量提升(hoisting),在进行代码的执行阶段时,a变量已经存在,且值为undefined

这种逻辑其实有些奇怪,我们对变量a进行声明和初始化赋值,是为了后面的逻辑和功能,但在进行初始化赋值前,变量a就已经可以进行访问,并且有值。

ES6中为了纠正这种现象,改变语法行为:对let和const声明的变量/常量,一定要在声明后使用,否则报错

console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initialization

let a = 1

在'暂时性死区'的概念中,let和const声明的变量/常量都规避了变量提升(hoisting)特性带来的怪异逻辑,让前端程序员在编写代码时,以更严谨的角度去进行编程,防止多余的误操作。

3.块级作用域

在ES6之前,只有全局作用域函数作用域,在ES6中,新增了块级作用域

块级作用域由一对大括号界定,在大括号内使用let和const进行声明,才会形成块级作用域

{

let a = 1;

console.log(a) // 1

}

console.log(a) // a is not defined


让我们来看一下,块级作用域存在前后的对比:

  • if执行语句中,var声明的变量直接作用于if语句所在的作用域内。

if(false){
var a = 1
}
console.log(a) // undefined

  • 可以通过下面这个例子,更直观地观察:没有块级作用域带来的场景误读。

var title = 1
function fun(){
if(title == undefined){
var title = 10
}
console.log(title) // 10
}
fun()fun函数中,使用var声明的title变量因变量提升(hoisting)特性,在执行前被提升到函数作用域顶部,且初始值为undefined,当进入执行阶段时,if判断为true,进入if执行语句,进行title的赋值操作。

这也是很多初学者一开始就会产生的疑问:

A:‘我明明是if判断成功,我才声明这个变量并初始化,那在这一步操作之前,title不应该是沿着作用域链去寻找全局作用域中的title吗?‘。

B:‘变量提升(hoisting)的特性’。

A:’那我肯定是要符合条件,才进入if执行语句,里面的代码才会执行,title这个变量才去初始化和赋值。现在变量提升不就导致了判断条件受到影响?'。

B:‘变量提升(hoisting)的特性’。

A: '......(按住自己的拳头)'。

这个对话可能有些绕,我们可以看图来解读这个同学的疑惑:

图片

  • 可以通过下面这个例子,更直观地观察:没有块级作用域带来的场景误读。

var title = 1
function fun(){
if(title == undefined){
let title = 10
}
console.log(title) // 1
}
fun()

  • for循环中var声明的计数变量直接作用于for语句所在的作用域内。

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

  • 拥有块级作用域后,可以避免用来计数的循环变量泄露。

function fun(){
for (let i = 0; i < 10; i++){
// ...
}
console.log(i); // i is not defined
}

  • 异步代码执行过程中,需要通过IIFE实现closure(闭包),达到打印目标。

function fun(){
for (var i = 0; i < 10; i++){
;(function(i){
setTimeout(()=>{
console.log(i); // 0 1 2 3 ...
})
})(i)
}
}

  • 拥有块级作用域后,不需要再通过closure(闭包)主动进行词法环境收集。

function fun(){
for (let i = 0; i < 10; i++){
setTimeout(()=>{
console.log(i); // 0 1 2 3 ...
})
}
}

总结

总结和了解var、let和const的特点后,我们才能明白"直接将var替换成let"这种做法携带的安全隐患有多大。

分析var和let/const的区别,必然要理清变量提升(Hoisting)、暂时性死区(TDZ)和块级作用域(block)这几个概念分别产生的效果。

let、const也是为了解决使用var时形成怪异逻辑的问题。通过规范的语法行为,统一代码的正确解读,减少代码在编写及运行时的误操作,提高代码的安全性和可读性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值