JavaScript对象构造函数内局部变量生命周期问题咨询
核心原因:JavaScript的闭包(Closure)机制
这是JS闭包的典型表现,和C/C++栈变量生命周期规则有本质区别,具体逻辑拆解开很容易理解:
- 先纠正从C/C++带过来的思维定式:JS里函数执行完退出的时候,不会直接销毁所有函数内的局部变量。JS的垃圾回收按可达性判断规则运行:只要一个变量还被存活的代码引用着,它就不会被回收,会一直保留在内存中。
- 这段示例代码里,
myNumbers中用let声明的n = 0,被内部定义的next函数捕获了:next在定义阶段,会把自身词法作用域里所有用到的外部变量,打包成独立的闭包环境和函数本身绑定。哪怕外层myNumbers已经执行完毕弹栈,这个闭包环境也会跟随next一同存活。 - 调用
myNumbers()拿到的返回对象持有next方法的引用,因此只要这个返回对象(即示例中外层const声明的n)没有被回收,next绑定的闭包环境里的局部变量n就会持续存在。每次调用next都是读写同一个变量,自然可以持续累加更新值,不会抛出ReferenceError。
拿C/C++逻辑类比可以快速理解:这个机制本质和你在C函数里用
malloc在堆上分配一个int变量,把指向该int的指针封装到结构体中返回,同时在结构体里存储操作这个int的函数指针的逻辑非常相似。区别只在于JS的闭包自动完成了堆分配、引用计数、生命周期管理的全流程,不需要手动释放内存,也不会像栈上分配的局部变量那样随函数返回直接销毁。
- 注意不要把它和全局静态变量混淆:每次调用
myNumbers()都会生成一套全新的独立闭包环境。比如你额外声明const m = myNumbers(),第一次调用m.next()返回值依然是10,和之前迭代器实例的累加结果完全独立、互不干扰。
// Home Made Iterable function myNumbers() { let n = 0; return { next: function() { n += 10; return {value:n, done:false}; } }; } // Create Iterable const n = myNumbers(); n.next(); // Returns 10 n.next(); // Returns 20 n.next(); // Returns 30
内容的提问来源于stack exchange,提问作者Michaël Di Giacomo
相关产品推荐
相关产品推荐

