块级作用域let&const

js给人的感觉往往是用起来比较简单,语法上宽松。这给开发者带来便利的同时也造成了一些违反思维习惯的别扭之处。es6一些新的特性的引入,可以认为试图纠正或补齐js最初设计的缺陷。

我们一起看一下letconst的引入对现有的编码方式会带来哪些影响。

变量声明提升

众所周知,变量声明提升是js中非常最重要的特性之一。也是面试中常被问到的点。但对于js新人来说可能觉得难以理解,甚至违反直觉。变量没有声明之前不应该能访问啊!

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

上面这段代码对于新手来说,undefined的结果是难以理解的。(心想不应该报错么?)

console.log(v1) // Uncaught ReferenceError: v1 is not defined
let v1 = 1
console.log(v1) // 1

使用let之后从逻辑上是符合开发者的思维习惯的 未声明之前使用就是会报引用错误,在声明之后访问变量的值正常返回变量值。

letconst声明的变量是不会被提升的,真正实现了使用前声明,声明后再使用。

全局变量不会变成window的属性

以前在全局作用域下声明变量时,全局变量自然而然的成为了全局对象的属性如:

var a = 1
console.log(window.a === a) // true

对于这种情况前端开发工程师早已烂熟于心了。letconst的引入同样改变了这种现象:

let a = 1
console.log(window.a) // undefined
console.log(a) // 1
window.a = 2
console.log(window.a) //2
console.log(a) // 1

作用域变量和对象属性分得清清楚楚。

for循环没有陷阱

看下这个前端圈用滥的面试题:

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

这题固然难不倒老鸟们。但新手们十有八九会答错。0 1 2 3 4 5

是的,从常理来说就应该是这样的,只不过js中缺少块级作用域的概念,var声明的变量自然而然从for循环的代码块外溢。

letconst引入后,每次循环都会创建特定于当次循环作用域的局部变量。换句话说每次循环都有与之绑定的i值。执行完成之后即销毁。不会外溢到外层作用域。下面的代码是符合预期的:

for(let i = 0; i<5; i++){
    setTimeout(function(){
        console.log(i) //0 1 2 3 4
    }, 0)
}
console.log(i) //  ReferenceError: i is not defined

最佳实践

为了避免代码中出现意外惊喜,日常coding中首先是使用const,可以有效避免变量被意外修改。如果变量有被修改的需求首选使用 letvar的使用尽量减少使用。


前端论道
414 声望10 粉丝