寫出執行以下代碼的結果:
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);
代碼運行的過程,在以下代碼中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>閉包堆棧的小題</title>
</head>
<body>
<script>
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); //=> undefined 0 1 1
// 輸出結果爲:undefined 0 1 1,執行過程如下:
/*
ECSTack:
EC(G):
VO(G):
Fun ,創建一個變量fun,並且創建一個堆,並將這個堆賦值給Fun,Fun = AAAFFF000。
var c = fun(0).fun(1); =>先創建變量c,然後執行fun(0),而後將結果.fun(1)執行,最後將這個結果賦值給變量c。執行結果如下:
因爲是函數,所以會創建有一個新的執行上下文,稱爲EC(FUN)1,也就是fun(0),裏面的內容爲:
變量對象:AO(FUN)1;作用域鏈爲:<--,VO(G)>
傳遞的實參個數,arguments=1
形參賦值:
n = 0,
o = undefined
代碼執行:
console.log(o) =>undefined
return {fun:function(m){return fun(m,n)}},在此返回一個對象,創建一個新的堆對象,名爲AAAFFF111,fun(0)執行後,要執行"結果.fun(1)",即AAAFFF111.fun(1),會產生一個新的執行上下文,anonymous是匿名的意思,可以稱上下文爲EC(AM)1,裏面的內容爲:
創建變量對象AO(AM)1 ; 作用域鏈<AO(AM)1,AO(FUN)1>
傳遞的實參個數,arguments=1
形參賦值:m=1
代碼執行:return fun(m,n),m是1,而n本作用域沒有,向上級找,在AO(FUN)1
中,n爲0,=>所以是return fun(1,0),先執行fun(1,0).然後將這個的函數結果返回,故創建新的上下文,再一次執行fun():
EC(FUN)2:=> fun(1,0)
創建變量:AO(FUN)2;作用域鏈:<AO(FUN)2,VO(G)>,上級作用域鏈是找在哪裏創建的,Fun是在全局創建的所以,是VO(G)
傳遞的實參個數,arguments=2
形參賦值:
n:1,
o:0
代碼執行:
console.log(o)=>0
return {
fun:function(){...}
},返回一個對象,在此是將這個返回的結果給c,所以這個return對象就是c,因是在AO(FUN)2中創建的,上級作用域就是AO(FUN)2。
c.fun(2);=>執行c中的fun函數,會創建新的執行上下文,EC(AM)2,傳個2 => AM(2):
創建變量對象AO(AM)2;作用域鏈:<AO(AM)2,AO(FUN)2>
傳遞的實參個數:arguments=1;
形參賦值:m=2;
代碼往下執行:
return fun(m,n)=> m是2,n在本作用域中沒有,向上級查找,就是AO(FUN)2中,n=1,即return fun(2,1),要執行fun(2,1),然後將執行結果返回,所以就是fun()第三次執行,會形成新的執行上下文,即EC(FUN)3: => fun(2,1)
裏面的執行:
創建新的變量對象AO(FUN)3;作用域鏈爲<AO(FUN)3,VO(G)>因爲fun是在全局創建,所以上級爲VO(G)。
fun(2,1) => 因爲在上述代碼中直接return fun(m,n),即fun(2,1),接下來就是執行fun(2,1):
傳遞的實參個數爲:arguments=2
形參賦值:
n:2,
o:1
代碼執行:
console.log(o) =>1
return{
fun:function(){...}
}
c.fun(3)=>執行c中的fun函數,會創建新的執行上下文,EC(AM)3,傳個3 => AM(3):
創建變量對象AO(AM)3;作用域鏈:<AO(AM)3,AO(FUN)2>
傳遞的實參個數:arguments=1;
形參賦值:m=3;
代碼往下執行:
return fun(m,n)=> m是3,n在本作用域中沒有,向上級查找,就是AO(FUN)2中,n=1,即return fun(3,1),要執行fun(3,1),然後將執行結果返回,所以就是fun()再次執行,會形成新的執行上下文,即EC(FUN)4: => fun(3,1)
裏面的執行:
創建新的變量對象AO(FUN)4;作用域鏈爲<AO(FUN)4,VO(G)>因爲fun是在全局創建,所以上級爲VO(G)。
fun(3,1) => 因爲在上述代碼中直接return fun(m,n),即fun(2,1),接下來就是執行fun(3,1):
傳遞的實參個數爲:arguments=2
形參賦值:
n:3,
o:1
代碼執行:
console.log(o) =>1
return{
fun:function(){...}
}
*/
</script>
</body>
</html>
如下圖: