作为初学入门的同学,总会在某个场合被问到 var 和 let 的区别。之前学习都是用 var, 怎么后面写代码就用 let ,甚至 const 了呢?
接下来就分享一下我对它们的认识。轻喷 …
首先我要非常武断的扔个观点:「 尽量用 const, 需要值改变时用 let , 不用 var 」
所谓区别,就是使用 let / const,相比于 var 的好处。轻喷 …
区别1:能否重复声明
通过 var 是可以重复声明定义变量的,根本不会报错,比如下面代码:
var a = 100
var a = 200 // 不会报错
console.log(a) // 输出 200
通过 let 重复声明定义变量时,则会报错
let b = 100
let b = 200 // 报错
事实上就算不赋值,只单纯的重复声明就是不行的,比如下面截图:
疑问:为什么 let 重复声明报错,要好于 var 不报错呢?
在实际工作编码中,相隔几十行的代码,用 var 定义变量极有可能覆盖之前已经存在的变量,导致代码没有得到预期的执行结果。但此时代码并不会报错,那么就给后期调试、排查错误增加了不少的时间成本。
如果使用 let , 编码过程中重复定义就会立即、明确的抛出错误,从而及时改正。(就像你的女朋友生气了,也不告诉你为啥,这种冷暴力。。。是吧)
区别2:作用域范围
作用域是指,变量声明定义后都可以在哪里使用。
let 声明的变量具有「块级作用域」,一般它的范围更小。比如下面:
例1:
{
var a = 100
let b = 100
}
console.log(a) // 输出100
console.log(b) // 报错 因为用 let 定义的 b,只能在 { } 中访问
例2:
if (true) {
let a = 100
}
console.log(a) // 报错 因为用 let 定义的 a, 只能在 { } 中访问
例3:
for (let i = 0; i < 5; i++) {
}
console.log(i) // 报错 因为用 let 定义的 i, 只能在循环结构中访问
例4:
for (let i = 0; i < 5; i++) {
let i = 2 // 此处的 i 与 上一行的 i 为两个不同变量.
// 也就是说 ( ) 是一个块级作用或, { } 是另一个块级作用域
// 它没有影响循环的次数
console.log('i love you')
}
在上面几个代码片段中, 换成 var , 作用域会变大, 后续可以访问到
疑问:为什么 let 更小范围的块级作用域,要好于 var 大范围作用域呢?
1.代码执行到变量作用域之外时,变量会被销毁,进而释放掉它所占用的内存。用 let 声明的变量,作用域更小,能更及时的释放掉内存空间。衡量代码效率的就是时间和空间,即更快的执行速度和更小的内存占用。
2.用 let 声明变量,出了作用域就会被销毁掉,这意味着在其它地方可以定义同名的变量,也不会冲突。它们是不同的变量。
区别3:是否变量提升
console.log( a )
var a = 100
上面的代码不会报错,它会输出 undefined, 执行的时候被会理解为下面的样子:
var a
console.log( a )
a = 100
这种现象被称为 「变量提升」
如果使用 let 声明变量,就直接报错,在变量声明前使用变量,这本身就是不对的,所以报错才是应该的。
区别4:是否挂载全局/顶层对象上
使用 var 声明的变量,以前普通函数都会默认挂载到全局的顶层对象上,通常会是浏览器中的 window 对象
var aaaa = 100
function bbbb() { console.log('i love you') }
console.log( window.aaaa ) // 输出 100
window.bbbb() // 调用函数, 输出 'i love you'
过多的内容挂载到 window 对象上,让它变得十分庞大,臃肿。
使用 let 就不会挂载到 window 对象上
let aaaa = 100
console.log( window.aaaa ) // undefined
关于 const
const 本意是定义常量,即定义赋值以后不能修改的量。
const a = 100
a = 200 // 报错
在 JS 编码中,大家的习惯是:
在定义对象、数组等复杂一点类型的变量时,尽量使用 const,因为它们为地址引用类型,地址是不变的,改变的是地址中保存的数据。
(个人觉得,这样破坏了代码的语义化,用定义常量的关键字声明定义一个变量,通过制造细节差异,给出一个“政治正确”的理由,最后体现出自己代码的”高端“,像极了18岁小伙子酷爱哲学,显得深刻的样子)也许是我没有领悟到吧~
const 除了定义后不能重新赋值以外, 与 let 性质相同