闭包思考题的理解
比较下面两段代码,试述两段代码的不同之处
// A-------------------------- var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f(); } checkscope(); // B--------------------------- var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f; } checkscope()();
核心区别:A 直接“把结果拿出来”,B 则“把能拿结果的工具递出来”
A 段代码 | B 段代码 | |
---|---|---|
checkscope 返回值 | 字符串 "local scope" |
内部函数 f (一个函数对象) |
外层执行上下文在函数返回后的状态 | 立即可被回收——没有任何外部引用再指向它 | 被 f 捕获,形成闭包;其词法环境在函数返回后仍然存活 |
调用方式 | checkscope() 一次调用就拿到字符串 |
第一次 checkscope() 得到函数,再调用一次 () 才拿到字符串 |
可复用性 | 不能复用;每次想得到值都得重新跑一遍 checkscope() |
可以复用;保存 var fn = checkscope(); ,之后多次 fn() 都能访问同一个 scope |
典型用途 | 立即求值的普通函数 | 需要持久化私有状态、做工厂函数/模块封装时 |
A 段
function checkscope() { var scope = "local scope"; function f() { return scope; } return f(); // **马上执行 f**,返回字符串 } checkscope(); // => "local scope"
-
创建并执行
checkscope
的执行上下文。 -
f()
立刻运行,读取同作用域链里最近的scope
(即"local scope"
)。 -
checkscope
返回这个字符串后结束;其执行上下文随即出栈并等待垃圾回收。
B 段
function checkscope() { var scope = "local scope"; function f() { return scope; } return f; // **返回函数本身**,不执行 } checkscope()(); // => "local scope"
-
第一次调用
checkscope()
:-
创建执行上下文,声明
scope
与f
。 -
返回函数对象
f
,但checkscope
的词法环境被f
闭包引用,无法回收。
-
-
紧接着对返回的函数再调用一次
()
:-
运行
f
时沿着保存的作用域链找到那份仍然存在的scope
,得到"local scope"
。
-
const getter = checkscope(); console.log(getter()); // "local scope" console.log(getter()); // 仍然是同一份 "local scope"
就能看出闭包让内部私有数据跨越了原本的生命周期。
总结一句话
-
A:只要立即用得到结果,闭包不会泄漏到外面。
-
B:把函数带着其私有数据“封装”出来,以后想用随时调用,典型闭包场景。