什么是[[Scopes]]中的Block块?for循环用let/var时为何存在差异?
什么是[[Scopes]]中的Block块
[[Scopes]]里的Block本质是块级作用域对象,是JavaScript引擎用来存储当前块内块级声明变量的内存结构,属于作用域链的一部分,只有当对应代码块存在块级声明时才会生成。
你观察到的for循环的差异,完全是var和let的声明特性导致的:
var不存在块级作用域,在for循环头部用var声明的变量i,实际属于外层的脚本/全局作用域,循环每一轮都共享同一个i变量,没有独立的存储空间,所以闭包的作用域链里不会出现额外的Block块,所有箭头函数最终引用的都是同一个i,值为循环结束后的4。- ES6之后
let/const支持块级作用域,且针对for循环头部的let声明有特殊处理:引擎会为每一轮循环单独创建一个独立的Block作用域,每一轮的i都是独立的变量副本,你代码中的每个箭头函数都捕获了对应轮次的Block作用域,所以在作用域链里能看到存储了对应i值的Block块,调用每个函数返回的i就是对应轮次的0、1、2、3。
Block块的创建规则
- 只有当代码块(包括
{}包裹的独立块、if/for/while/switch等语句的关联代码块)中存在let/const/class这类块级声明时,JavaScript引擎才会为这个代码块创建对应的Block作用域对象。 - 若代码块内只有
var声明、普通函数调用等无块级变量的内容,不会生成独立的Block块。 - 针对for循环的特殊规则:即便循环体没有显式的
{}包裹,只要循环头部用let/const声明变量,每一轮循环都会单独创建一个Block块,存储当前轮次的循环变量值,保证各轮次的变量互相独立。 - 若块内没有被外部闭包引用的变量,Block块会在代码块执行结束后被垃圾回收;只有当块内定义的函数(闭包)被外部引用保留时,对应的Block块才会被保留在闭包的[[Scopes]]作用域链中,这也是你在打印的函数作用域里能看到Block的原因。
内容的提问来源于stack exchange,提问作者devumesh
相关产品推荐
相关产品推荐

