首先看如下**,你是否了解其真正的意義:
function test()local i=0
return function()
i=i+1
return i
endenddotest=test()
print(dotest()) --輸出1
print(dotest()) --輸出2
你可能有這樣的疑問:
1. 呼叫test()返回的函式dotest()時,變數 i 的定義在哪?
2. test()中的i不是區域性變數嗎?為什麼返回的函式還能呼叫。
詞法定界:當乙個函式內巢狀另乙個函式的時候,內函式可以訪問外部函式的區域性變數,這種特徵叫做詞法定界。而這些變數就被稱為該內嵌函式的upvalue,upvalue實際指的是變數而不是值,這些變數可以在內部函式之間共享。
閉包:通過呼叫含有乙個內部函式加上該外部函式持有的外部區域性變數(upvalue)的外部函式(外部函式就是工廠)產生的乙個例項函式。
閉包組成:外部函式+外部函式建立的upvalue+內部函式(閉包函式)
如上面的函式test(),
test()就是外部函式,
外部函式的區域性變數local i=0就是upvalue(也叫做非區域性變數,之所以叫做非區域性變數,是因為此變數的作用域既不是區域性變數的作用域,也不是全域性變數的作用域。),
返回的函式就是內部函式。
現在再回頭看看原來的函式,我們知道了這種形式的函式叫做閉包函式。而test()中的區域性變數i是內嵌函式的upvalue(非區域性變數),且在內部函式中共享。
重複呼叫內部函式時,每乙個呼叫都會記住上一次呼叫後的值,就是說第一次呼叫dotest()之後,i 的值已經是1了。
下面再看個例子
function test()local i=0
return function()
i=i+1
return i
endenddotest=test()
doagain=test()
print(dotest()) --輸出1
print(dotest()) --輸出2
print(doagain()) --輸出1
print(doagain()) --輸出2
可以看到,此時執行doagain()時 i 值並沒有在原來的基礎上增加。
原因是:
dotest,doagain是建立在同乙個函式,同乙個區域性變數的不同例項上面的兩個不同的閉包。
呼叫一次test()就會產生乙個新的閉包, 而閉包中的upvalue各自獨立。所以不難解釋為什麼doagain()的i 值為什麼沒有在原來的基礎上增加了。
function list_iter(t) --外包函式叫做工廠函式。local i=0
local n=table.getn(t)
return function()
i=i+1
if i<=n then return t[i] end
endend
--[[這裡的list_iter是乙個工廠,每次呼叫都會產生乙個新的閉包。該閉包內部包括了upvalue(t,i,n)。
在while中使用:
--while中使用:t=iter=list_iter(t) --呼叫迭代器產生乙個閉包
while true do
--當閉包函式的i值已經等於n的值時,依然會執行閉包函式,此時返回的就是nil.
--如果沒有下面的判斷,while就會一直迴圈,並進入死迴圈。
local element=iter()
if element==nil then break end
print(element)
end
在泛型for使用
--泛型for使用:t=--這裡的list_iter()工廠函式只會被呼叫一次產生乙個閉包函式,
--後面的每一次迭代都是用該閉包函式,而不是工廠函式。
for element in list_iter(t) do
(element)
end如果想要同時返回k,v值,需要修改工廠函式,如下所示:
function
list_iter(tb)
local i = 0
return
function
() i = i + 1
--如果沒有下面這個判斷,就會一直執行。
--詳情可以看我的另一篇部落格,《lua內容關於for迴圈的總結》
if tb[i] ==nil then
return
nil
endreturn i,tb[i]
endend
什麼是閉包?為什麼使用閉包?閉包的缺點?
閉包 即重用乙個變數,又保護變數不被汙染的一種機制。為什麼使用閉包 全域性變數和區域性變數都具有不可兼得的優缺點。全域性變數 優 可重用,缺 易被汙染。區域性變數 優 僅函式內可用,不會被汙染。缺 不可重用 何時使用 只要即重用乙個變數,又保護變數不被汙染時。如何 3步 1.用外層函式包裹要保護的變...
什麼是閉包
什麼是閉包 閉包說的通俗一點就是打通了一條在函式內部訪問函式內部作用域的通道。正常情況下,函式外部是訪問不了內部作用域變數的,表象判斷是不是閉包 函式巢狀函式,內部函式被return 內部函式呼叫外層函式的區域性變數。優點 可以隔離作用域,不造成全域性渲染。缺點 由於閉包長期駐留記憶體,則長期這樣會...
什麼是閉包
理解閉包需要先了解 作用域 作用域是指當前執行 對變數的訪問許可權 分為靜態作用域和動態作用域,js採用靜態作用域 其區別是 靜態作用域 函式作用域是在函式定義時決定,動態作用域 函式作用域是在函式呼叫時定義 es6的塊級作用域 通過let 和 const 宣告,只能在宣告變數所在的作用域裡使用,外...