[Musings]
一篇文章搞清楚 JS 变量提升
最基础的变量提升
1 | var a = 100; |
真正的运行的时候编译器其实偷偷做了这一步:
1 | var a = 100; |
行,这是第一步,变量提升,接着看看函数提升
1 | var a = 100; |
看完变量和方法的变量提升,我们来看看 let 和 const
1 | let a = 100; |
接着我们继续看看方法体作用于中的情况
1 | (function test() { |
基本到这差不多就能理解变量提升了,但是有一种比较特殊的异步+变量提升的问题
1 | (function test() { |
解释下这里发生这个情况的原因:
简洁的表达就是
“var 让所有回调共享同一个变量引用,最终都看到循环结束值 3。let 每次迭代创建新的词法环境,每个回调捕获独立的变量值。”
我脑子里的啰嗦想法就是 ⬇️
var 的作用域是函数作用域而 let 的作用与是块级作用域,所以这里所有的异步任务会被丢到异步队列,然后在执行 log 的时候,i 已经变成 3 了,所以输出了三遍
而 let 是块级作用域,所以在执行的时候每一个 log 函数都带一个变量 i,每个变量 i 在单独的内存空间里,所以不会互相污染,这就是 var 导致的变量提升所带来影响,从本身的额块级作用域被提升到了函数作用域,所以被 log 函数共享了内存空间
以上我的讲解都是自己的理解,实际上对于 let i 的变量在内存中都是独立的这点,得根据 javascript 引擎的写法来看,可能引擎会重用寄存器中的地址所以从
描述规范上来说,更准确的讲法是,let i 在词法环境里是互相隔离的
继续变量提升的case:
1 | console.log(typeof func); // "function" ✅ |
显而易见,函数提升的优先级高于变量
最后感受下块级作用域的隔离
1 | { |
最后附上一个对比图吧
| 特性 | var | let/const | 函数声明 |
|---|---|---|---|
| 提升 | ✅ | ⚠️暂时性死区 | ⚠️暂时性死区 |
| 作用域 | 函数级 | 块级 | 块级 |
| 重复说明 | ✅ | ❌ | ❌ |
| 异步闭包 | 共享应用 | 独立 | 独立 |