iT邦幫忙

0

JS 閉包求解

  • 分享至 

  • xImage
function fun(n,o){
    console.log(o)
    return{
        fun:function(m){
            return fun(m,n);
        }
    }
}
var a = fun(0);a.fun(1); a.fun(2); a.fun(3);
//undefined,0,0,0
var b = fun(0).fun(1).fun(2).fun(3);//undefined,0,1,2
var c = fun(0).fun(1); c.fun(2); a.fun(3);//undefined,0,1,0

最近在網路上學習JS高級,但是閉包的這題我搞不懂
來源:
https://www.bilibili.com/video/BV14s411E7qf/?p=36

console.log(o),我這邊改成console.log(m,o),可以知道
var a = fun(0);a.fun(1); a.fun(2); a.fun(3);
0,1,2,3都傳給了m,而o一開始是undefined,
閉包=>
內部函數function(m){return fun(m,n);}
引用了外部函數的數據console.log(o)
o一開始就是undefined,也一直沒有傳數據進去,
a.fun(1); a.fun(2); a.fun(3);為什麼o會變成0?
下面的
var b = fun(0).fun(1).fun(2).fun(3);//undefined,0,1,2
var c = fun(0).fun(1); c.fun(2); a.fun(3);//undefined,0,1,0
這部分我也搞不懂

我後來用答案推演過程,大概知道原因。
var a = fun(0);是傳值function fun(n,o){console.log(o)...
n=0,o=undefined
後面的a.fun(1); a.fun(2); a.fun(3);是直接執行
fun:function(m){return fun(m,n);然後再return
所以1,2,3都是傳m;
n則是抓外部原本就存在的n=0,return 後n都是以0的值傳給o

所以console.log(o)就會一直是 0

但是靠事後諸葛,閉包這塊感覺跟不懂還是一樣,不曉得有沒有大老能夠講解。

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

5
alien663
iT邦研究生 4 級 ‧ 2023-03-16 14:48:14
最佳解答

要理解這個,首先你要知道階層的概念,var a = fun(0)這行宣告之後,要有以下概念

a.n => 0
a.o => undefined (output)
a.fun => 新的fun(輸入值1, a.n)

然後,a.fun可以無限往下長,以此類推:

a.n => 0
a.o => undefined (output)
a.fun => 新的fun(輸入值1, a.n)
    | a.fun.n => 輸入值1
    | a.fun.o => a.n (output)
    | a.fun.fun => 新的fun(輸入值2, 輸入值1)
            | ...
            | ...
            | ...

有了這種階層概念,就會比較好理解為什麼輸出會是那樣。

第一題

a = fun(0) => undefined (因為沒有給值)
a.fun(1) => a.n (一開始的輸入 : 0)
a.fun(2) => a.n (一開始的輸入 : 0)
a.fun(3) => a.n (一開始的輸入 : 0)

第二題

var b = fun(0) => undefined (因為沒有給值)
var b = fun(0).fun(1) => a.n (上一行的輸入 : 0)
var b = fun(0).fun(1).fun(2) => 輸入值1 (上一行的輸入 : 1)
var b = fun(0).fun(1).fun(2).fun(3) => 輸入值2 (上一行的輸入 : 2)

第三題

var c = fun(0).fun(1) => undefined, 0 (同第二題)
c.fun(2) => 1 (因為c是被賦予fun(1)的結果,所以根據fun(1)作為上一階繼續)
a.fun(3) => 0 (同第一題)

rain_yu iT邦研究生 5 級 ‧ 2023-03-17 10:46:52 檢舉

其實我最不明白的是
a = fun(0)
function fun(n,o)//n=0,o=undefined

為什麼
fun(1)的時候
function(m){return fun(m,n);}
m=1這沒問題;但n=0,
如果說n的值抓的是function fun(n,o)的n值(同名稱)?

那return的時候,為什麼n值是傳給o(同位置)
是不是我基礎沒搞好QQ

alien663 iT邦研究生 4 級 ‧ 2023-03-17 11:44:11 檢舉

我大概知道你的問題了。
這個範例在return時,是回傳一個function,而不是數值,在其他語言中比較通用的稱呼應該是叫做lambda。這是一個將function當作變數來傳遞和使用的招數,最為經典的應該要屬lisp這個語言。
lambda簡單的用法也可以像下面這樣:

function test(a, b){   
    return {
        Add:function(){console.log(a + b)}
    }
}
test(1, 2).Add()

如果你直接呼叫test(1, 2).Add,那你會得到一個函數,這證明了該參數的值其實是一整個function,而加上()的目的是為了將他視為函數去執行。

如果說n的值抓的是function fun(n,o)的n值(同名稱)?

還記得我說的階層概念嗎,由於回傳的是一個function,並不是數值,所以直到你呼叫這個回傳的function才會開始執行程式碼,會一路從children呼叫回去parent去要資料,這是callback的部分,學JS要讀熟這塊才行。

階層概念有大概之後,再去理解這題的程式碼,就會知道這程式碼只是一個children顯示parent的參數的小程式。
所以以第一題來說,fun(1)、fun(2)、fun(3)都是fun(0)的child,顯示的就會是fun(0)的參數n

第二題的狀況就是:fun(0)生下fun(1)生下fun(2)生下fun(3)
所以顯示的就會是undefined、0、1、2

當你一、二題都完全理解,第三題就是送分了。

我要發表回答

立即登入回答