函数声明是否为非静态?JS闭包中useState模拟代码的变量存储疑问
闭包与变量存储:模拟useState中x的去向解析
嘿,这个问题问到了闭包最关键的核心机制,我来一步步给你拆解清楚:
首先直接回答你的疑问:x并不存在于useState的原始函数声明里,而是存在于useState()被调用时创建的执行上下文的变量环境中,是闭包机制让这个变量被保留了下来,而不是随着函数执行完毕被销毁。
我们一步步走一遍代码的执行流程:
- 当你调用
const [getX, setX] = useState();时,useState函数开始执行:- 此时会创建一个全新的执行上下文,里面包含了局部变量
x(初始值为0); - 然后返回两个匿名函数,这两个函数的内部属性
[[Environment]]会指向这个执行上下文的变量环境(简单说就是它们“记住”了这个x所在的环境)。
- 此时会创建一个全新的执行上下文,里面包含了局部变量
- 当
useState执行完毕后,正常情况下它的执行上下文会被垃圾回收机制销毁,但因为返回的getX和setX还在外部被引用着,所以这个包含x的变量环境会被保留下来——这就是闭包的本质:函数可以访问并保留其定义时所在的词法环境,即使函数在词法环境之外执行。 - 当你调用
getX()时,它会沿着作用域链找到这个被保留的变量环境里的x,输出当前值;调用setX(1)时,同样是找到这个x并修改它的值,所以再次调用getX()会输出1。
关于你提到的“函数声明不可更改”的误解:
你之前觉得JavaScript函数声明“不可更改”,其实和这个场景是两回事:
- 函数声明的“不可更改”指的是函数标识符本身的引用不能被重新赋值(比如你不能在之后再写
function useState() { ... }来覆盖原来的声明); - 但函数内部的局部变量,在闭包的作用下,是可以被保留、被后续的闭包函数修改的——这和函数声明本身能不能被更改完全无关。
举个更通俗的例子:闭包就像useState给你做了一个专属的小盒子,把x放在里面,然后给你两把钥匙(getX和setX)。不管你在外面什么时候用这两把钥匙,打开的都是同一个盒子里的x,而这个盒子会一直存在,直到你不再持有这两把钥匙(也就是getX和setX被销毁)。
内容的提问来源于stack exchange,提问作者Pavlos Karalis
相关产品推荐
相关产品推荐

