【发布时间】:2020-07-24 04:34:21
【问题描述】:
我正在尝试了解与 javascript 中的调用堆栈相关的 javascript 闭包。
我遇到了一个闭包的例子
function a() {
let grandpa = 'grandpa'
return function b() {
let father = 'father'
return function c() {
let son = 'son'
return `${grandpa} > ${father} > ${son}`
}
}
}
let x = a();
let y = x();
y();
现在根据我对调用堆栈的理解,当我们调用函数 a() 时,它会被压入堆栈,然后当我们运行函数 'b' 时,它会被压入 'a' 然后函数 'c' 上'b'。所以在我看来它应该是这样的
但是,我遇到的这个例子的解释显示了闭包的含义:-
“当我们调用函数'a'时,我们得到的返回是函数'b',在返回'b'之后,函数'a'从堆栈中弹出,因此它的变量环境被删除(垃圾收集的概念 -标记和扫描算法)。 但是,函数 'c' 仍然可以访问变量 'grandpa' 和 'father' "
根据我的理解,JS调用栈遵循先进后出(或者说后进先出)的概念。 因此,如果调用堆栈遵循 LIFO,那么为什么 a() 在 c() 之前从堆栈中弹出,不应该先弹出 c() 然后 b() 然后 a() 吗??
感觉这里的闭包解释和我对调用栈的理解是相反的。
如果有人能解释这个闭包示例以及调用堆栈,我将不胜感激?
【问题讨论】:
-
因为
a()执行完毕。一旦完成,它就会从调用堆栈中删除 - 完成。当您调用b()(通过x()()时,您正在执行一个new函数调用,该函数调用完成并返回c(将其分配给y)。 -
@VLAZ 所以如果函数已经完成执行,即使它首先进入堆栈也会被删除??您能否确认我对堆栈的理解是否正确??
-
堆栈是 LIFO,是的 I've wrote about it before。如果你有类似
a = () => b()的东西,那么调用a()会将a推入堆栈,然后b一旦b得到解决,你就会回到a的堆栈框架,一旦完成,你回到了前一个堆栈帧(如果有的话)。但是,您实际上有a =() ={}和b = () =>{}然后依次调用它们,这样您就不会为它们获得嵌套的堆栈帧。 -
闭包是关于作用域链的。它们与调用堆栈无关。
标签: javascript closures callstack