VueBloghyhero6

简说var 、 let 、 const 区别

2019-11-21 / 2019-11-21 / 355次浏览
  1. JS 没有块级 作用域 但是JS 有函数作用域。
    for ( var i = 0; i < 10; i ++ ) {
    var a = 'a';
    }

    console.log( a ) // a
    or
    console.log( i ) // 10
    上述代码可以足以表明函数没有块级作用域,明显外部可以接收到内部的一个值。

接着往下看
for(var i = 0; i < 10; i++) {
console.log(i)
}

这个 输出 一定是从 0 到 9 没啥好说的

下面的这个重点

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

输出 10个 10 ,这个就很难受了,这么写代码 的都是 想单个去输出i 的值。由于没有块级别作用域做缓存(个人是这么解释的可能不太对)。但是没有ES6 你说想解决这个问题咋办。OK 很好办。采用闭包 。这个咱们之后在实现,也比较容易。

这里引出了块级作用域
我们引入 阮一峰老师的 es6 教程 的代码
var a = []
for ( var i = 0; i < 10; i ++ ){
a[i] = function () {
console.log( i )
}
}

a[6] () // 10
可以看出 和上面的问题是一个问题,同样的问题。

var a = []
for ( let i = 0; i < 10; i ++ ){
a[i] = function () {
console.log( i )
}
}

a[6] () // 6

我们直接使用let,解释:
因为 es5 不存在块级作用域,所以迭代变量i 泄露了,然后对于a 数组 内 每一个函数内的 i 都是 向上 查询 作用域 a 的 ,所以结果是10

上面代码中,变量 i 是let 声明的,当前的i 只在本轮循环有效,所以每一次循环的i 其实 都是一个新的变量,所以最后输出的结果是6.

疑问:

我想不通 每一次循环的i 其实 都是一个新的变量,这个过程是怎么样的,如果我理解为每次迭代都是新的一个作用域,那么迭代变量的迭代( i++ ) 是如何传递给下一个块级作用域呢。

阮一峰老师的最新文档上面也给出了解释

你可能 会问,如果每一轮的变量i 都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮的值? 这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i 时,就在上一轮的基础上进行计算。

另外,for 循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

参考网址
https://segmentfault.com/q/1010000007541743

下面 在看 几个let 的特性

let a = 'a'

let a = 'b' // 这样浏览器会直接抛出报错 重复定义使用

a = 'b' // 但是我测试 a = b 是可行的。

比较 懒了 直接上个图。

const 就是定义常量的比较严格别瞎用就行,而let 是块级作用域,这个咱们已经反复提到了。

回过头来我们再看这个部分的代码 把 var 换成 let
for ( let i = 0; i < 10; i ++ ) {
let a = 'a';
}

console.log( a ) // 直接 抛出报错a 是未定义的
console.log( i ) // 一样抛出 i 是未定义的

let 声明块级作用域外面吃不到很正常。

回到上面 定时器 一直输出10的问题,setTimeout 属于异步定时器,由于异步任务,0 它 异步中, 1 他 异步 中,浏览器那就挂着呗,这个解释涉及到事件循环了,eventloop ,想了解的可以去搜下,我博客也有。结果都是到了 10 ,全跑了一遍, setTimeout 说 我好了, 一看i 全是 10。 那怎么办

for(let i = 0; i < 10; i++) {
setTimeout(function() { console.log(i)}, 1000)}

输出 0 1 2 3 4 5 6 7 8 9
let 块级作用域牛逼,

我们使用闭包可以实现同样的代码
for ( var i = 0; i < 10; i ++ ) {
var a = 'a';
(function( i ){
setTimeout(function() { console.log(i)}, 1000)
})(i)
}

输出 0 1 2 3 4 5 6 7 8 9

最后,不求成为大神,看完上述起码对let 块级作用域有一个简单的认知。

最最后 老规矩

参考
https://www.jianshu.com/p/4e9cd99ecbf5