本章触及3个知识点,var、let、const,如今让我们相识3个关键字的特征和运用方法。
var
JavaScript中,我们一般说的作用域是函数作用域,运用var声明的变量,无论是在代码的哪一个处所声明的,都邑提拔到当前作用域的最顶部,这类行动叫做变量提拔(Hoisting)
也就是说,假如在函数内部声明的变量,都邑被提拔到该函数开首,而在全局声明的变量,就会提拔到全局作用域的顶部。
function test() {
console.log('1: ', a) //undefined
if (false) {
var a = 1
}
console.log('3: ', a) //undefined
}
test()
现实实行时,上面的代码中的变量a会提拔到函数顶部声明,纵然if语句的前提是false,也一样不影响a变量提拔。
function test() {
var a
//a声明没有赋值
console.log('1: ', a) //undefined
if (false) {
a = 1
}
//a声明没有赋值
console.log('3: ', a) //undefined
}
在函数嵌套函数的场景下,变量只会提拔到近来的一个函数顶部,而不会。
//b提拔到函数a顶部,但不会提拔到函数test。
function test() {
function a() {
if (false) {
var b = 2
}
}
console.log('b: ', b)
}
test() //b is not defined
假如a没有声明,那末就会报错,没有声明和声明后没有赋值是不一样的,这点肯定要区离开,有助于我们找bug。
//a没有声明的状况
a is not defined
let
let和const都能够声明块级作用域,用法和var是相似的,let的特点是不会变量提拔,而是被锁在当前块中。
一个异常简朴的例子:
function test() {
if(true) {
console.log(a)//TDZ,俗称暂时死区,用来形貌变量不提拔的征象
let a = 1
}
}
test() // a is not defined
function test() {
if(true) {
let a = 1
}
console.log(a)
}
test() // a is not defined
唯一准确的运用方法:先声明,再接见。
function test() {
if(true) {
let a = 1
console.log(a)
}
}
test() // 1
const
声明常量,一旦声明,不可变动,而且常量必需初始化赋值。
const type = "ACTION"
我们尝尝从新声明type,看看会报什么错:
const type = "ACTION"
type = 1
console.log(type) //"type" is read-only
const type = "ACTION"
let type = 1
console.log(type) //Duplicate declaration "type"
const虽然是常量,不许可修正默许赋值,但假如定义的是对象Object,那末能够修正对象内部的属性值。
const type = {
a: 1
}
type.a = 2 //没有直接修正type的值,而是修正type.a的属性值,这是许可的。
console.log(type) // {a: 2}
const和let的异同点
相同点:const和let都是在当前块内有效,实行到块外会被烧毁,也不存在变量提拔(TDZ),不能反复声明。
不同点:const不能再赋值,let声明的变量能够反复赋值。
暂时死区(TDZ)
上面我们也提到了TDZ的场景,那末,有什么用呢?答案就是没什么用。
暂时死区的意义是在当前作用域的块内,在声明变量前的地区叫做暂时死区。
if (true) {
//这块地区是TDZ
let a = 1
}
块级作用域的运用场景
除了上面提到的经常使用声明体式格局,我们还能够在轮回中运用,最着名的一道面试题:轮回中定时器闭包的考题
在for轮回中运用var声明的轮回变量,会跳出轮回体污染当前的函数。
for(var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i) //5, 5, 5, 5, 5
}, 0)
}
console.log(i) //5 i跳出轮回体污染外部函数
//将var改成let以后
for(let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i) // 0,1,2,3,4
}, 0)
}
console.log(i)//i is not defined i没法污染外部函数
关于这个运用场景的具体剖析能够检察我写的别的一篇文章:JavaScript同步、异步、回调实行递次之典范闭包setTimeout面试题剖析
在全局作用域声明
假如在全局作用域运用let或许const声明,当声明的变量自身就是全局属性,比方closed。只会掩盖该全局变量,而不会替换它。
window.closed = false
let closed = true
closed // true
window.closed // false
最好实践
在现实开辟中,我们挑选运用var、let照样const,取决于我们的变量是否是须要更新,一般我们愿望变量保证不被歹意修正,而运用大批的const,在react中,props通报的对象是不可变动的,所以运用const声明,声明一个对象的时刻,也引荐运用const,当你须要修正声明的变量值时,运用let,var能用的场景都能够运用let替换。