function fun (n,o){
console.log(o);
return {
fun:function(m){
return fun(m, n);
};
};
};
var c = fun(0).fun(1);
c.fun(2);
c.fun(3);
图形解析:
文字步骤解析:
- 全局上下文中进行变量提升。
function fun (n,o){...};
,函数在变量提升阶段,定义加赋值。-> function fun = 0x000
。var
关键字声明的变量,在变量提升阶段,只声明不定义->var c (默认undefined)
。
- 代码执行:
function fun (n,o){...};
,函数在变量提升阶段,定义加赋值过,此处直接跳过。var c = fun(0).fun(1);
var c
变量提升阶段提升阶段已经处理过,只需要把等号右侧运算出来,把结果赋值给全局变量c
即可。- 运算
fun(0).fun(1);
分两步骤运算:- 第一步:
fun(0) => 0x000(0)
,- 初始化作用域链 /初始化this/ 变量提升…
n = 0, o = undefined
- 代码执行:
console.log(o);
=>第一次输出 ‘undefined’。return {... }; => 0x001
- 得出运算结果对象堆
0x001
。
- 初始化作用域链 /初始化this/ 变量提升…
- 第二步,
0x000(0).fun(1)
:对象堆0x001
中的函数堆0x002
执行,并传参数1,-> 0x002(1)
;- 初始化作用域链 /初始阿虎this/ 变量提升…
m = 1
。 - 代码执行:
return fun(m, n);
- 此处是第二次运行全局函数fun,并传参m ,n
-> 0x000(1, 0)
。- 初始化作用域链 /初始化this/ 变量提升…
n = 1,0 = 0
。 - 代码执行:
console.log(o);
=>第二次输出 ‘0’。return {... }; => 0x003
- 初始化作用域链 /初始化this/ 变量提升…
- 返回新的对象堆
0x003
。
- 此处是第二次运行全局函数fun,并传参m ,n
- 初始化作用域链 /初始阿虎this/ 变量提升…
- 返回新的对象堆 0x003返回给上下文EC(AN)
- 第一步:
- 再把返回的对象堆
0x003
赋值给全局的变量c
。 - 此时上下文
EC(AN)
中对象堆被上下文以外的全局变量从c
占用了,所以上下文EC(AN)不能被释放,就形成了闭包。
c.fun(2);
:- 执行变量c的对象堆
0x003
中的函数堆fun: 0x004
,并传入参数 2=>fun(0) => 0x000(2)
。 - 初始化作用域链 /初始阿虎this/ 变量提升…
m = 2
。 - 代码执行:
return fun(m, n);
- 此处是第三次运行全局函数fun,并传参m ,n
-> 0x000(2, 1)
。- 初始化作用域链 /初始化this/ 变量提升…
n = 2,0 = 1
。 - 代码执行:
console.log(o);
=>第三次输出 ‘1’。return {... }; => 0x005
- 返回新的对象堆
0x005
- 初始化作用域链 /初始化this/ 变量提升…
- 此处是第三次运行全局函数fun,并传参m ,n
- 返回的对象没有被占用,所以当前上下文出栈释放。
- 执行变量c的对象堆
c.fun(3);
:- 执行变量c的对象堆
0x003
中的函数堆fun: 0x004
,并传入参数 3=>fun(0) => 0x000(3)
。 - 初始化作用域链 /初始阿虎this/ 变量提升…
m = 3
。 - 代码执行:
return fun(m, n);
- 此处是第三次运行全局函数fun,并传参m ,n
-> 0x000(3, 1)
。- 初始化作用域链 /初始化this/ 变量提升…
n = 3,0 = 1
。 - 代码执行:
console.log(o);
=>第四次输出 ‘1’。return {... }; => 0x007
- 返回新的对象堆
0x007
- 初始化作用域链 /初始化this/ 变量提升…
- 此处是第三次运行全局函数fun,并传参m ,n
- 返回的对象没有被占用,所以当前上下文出栈释放。
- 执行变量c的对象堆