有段代码如下:
function createCounter(){ let i=0; function increment(){ i++; } function getValue(){ return i; } return {increment,getValue} } const counter = createCounter();
在这段代码中,运用了函数的3个特点:
-
在函数内部生成了一个局部的变量 i;
-
嵌入了 increment 和 getValue 这两个函数方法;
-
把函数作为返回值用 return 来返回
当执行完createCounter函数后,按道理相关变量 i 应该被销毁了,并完成相关的垃圾回收。但是我们仍然可以访问它内部的变量 i,并可以继续调用 increment 和 getValue 方法。当我们尝试增加 i 的值的时候,会看到返回不断增加的结果。
counter.increment(); counter.getValue(); // 返回1 counter.increment(); counter.getValue(); // 返回2
原理解析如下,当 JavaScript 引擎解析函数的时候,用的是延迟解析,而不是及时解析。这样做的目的是减少解析时间和减少内存使用。所以在语法解析的时候,只会解析到 createCounter 函数这一层,而不会继续解析嵌入的 increment 和 getValue 函数。
但是引擎同时又有一个预解析的功能,可以看到 increment 和 getValue 会引用一个外部的变量 i,所以会把这个变量从栈移到堆中,就用了更长的记忆来记录 i 的值。
有一点要注意的是,考虑到性能、内存和执行速度,当使用闭包的时候,我们就要注意尽量使用本地而不要用全局变量。