一個函數可以傳回一個計算結果,也可以傳回一個函數。
傳回一個函數時,牢記該函數并未執行,傳回函數中不要引用任何可能會變化的變量。
簡單了解:
cc: cc:
簡單了解就是r1隻是函數指針
cc:
r1()才執行函數
執行的時候才開始初始化值。
# fs = []
# for i in range(1, 4):
# def f():
# return i*i
# fs.append(f)
# r1,r2,r3 = fs
# print(r1())
# print(r2())
# print(r3())
Reads: 276649
高階函數除了可以接受函數作為參數外,還可以把函數作為結果值傳回。
我們來實作一個可變參數的求和。通常情況下,求和的函數是這樣定義的:
但是,如果不需要立刻求和,而是在後面的代碼中,根據需要再計算怎麼辦?可以不傳回求和的結果,而是傳回求和的函數:
當我們調用<code>lazy_sum()</code>時,傳回的并不是求和結果,而是求和函數:
調用函數<code>f</code>時,才真正計算求和的結果:
在這個例子中,我們在函數<code>lazy_sum</code>中又定義了函數<code>sum</code>,并且,内部函數<code>sum</code>可以引用外部函數<code>lazy_sum</code>的參數和局部變量,當<code>lazy_sum</code>傳回函數<code>sum</code>時,相關參數和變量都儲存在傳回的函數中,這種稱為“閉包(Closure)”的程式結構擁有極大的威力。
請再注意一點,當我們調用<code>lazy_sum()</code>時,每次調用都會傳回一個新的函數,即使傳入相同的參數:
<code>f1()</code>和<code>f2()</code>的調用結果互不影響。
注意到傳回的函數在其定義内部引用了局部變量<code>args</code>,是以,當一個函數傳回了一個函數後,其内部的局部變量還被新函數引用,是以,閉包用起來簡單,實作起來可不容易。
另一個需要注意的問題是,傳回的函數并沒有立刻執行,而是直到調用了<code>f()</code>才執行。我們來看一個例子:
在上面的例子中,每次循環,都建立了一個新的函數,然後,把建立的3個函數都傳回了。
你可能認為調用<code>f1()</code>,<code>f2()</code>和<code>f3()</code>結果應該是<code>1</code>,<code>4</code>,<code>9</code>,但實際結果是:
全部都是<code>9</code>!原因就在于傳回的函數引用了變量<code>i</code>,但它并非立刻執行。等到3個函數都傳回時,它們所引用的變量<code>i</code>已經變成了<code>3</code>,是以最終結果為<code>9</code>。
傳回閉包時牢記一點:傳回函數不要引用任何循環變量,或者後續會發生變化的變量。
如果一定要引用循環變量怎麼辦?方法是再建立一個函數,用該函數的參數綁定循環變量目前的值,無論該循環變量後續如何更改,已綁定到函數參數的值不變:
再看看結果:
PYTHON<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>>>JS
let funArr = []
for (var i of [1, 2, 3]) {
function f () {
return i * i
}
funArr.push(f)
console.log(funArr)
console.log(
funArr[0]()
)
funArr[1]()
funArr[2]()