題記:
閉包是許多語言都支持的特性,像javascript,lua等。對閉包函數有所了解的童鞋可能都會感嘆閉包函數似乎做到了其他普通函數未能做到的事情。
普通函數內部可以直接讀取全局變量。如:
local n = 1 function f1( ... ) return n end print(f1()) --1
但普通函數內部卻無法讀取一個與自己不同作用域的局部變量。如:
function f1( ... ) local n = 1 return n end function f2( ... ) print(n) end f2() --nil
但是通過下列這種特殊的函數寫法,就可以讓一個函數讀取一個與自己不同作用域的局部變量:
function f1( ... ) local n = 1 function f2( ... ) n = n + 1 return n end return f2 end local result = f1() print(result()) --2
在上面的代碼中,函數f2就被包括在函數f1內部,這時f1內部的所有局部變量,對f2都是可見的。但是反過來就不行,f2內部的局部變量,對f1 就是不可見的。
既然f2可以讀取f1中的局部變量,那么只要把f2作為返回值,我們就可以在f1外部讀取它的內部變量!
這種函數叫稱之為閉包函數。
所以,如果要用一句話說明白閉包函數,那就是:函數內在包含子函數,並最終return子函數。
而閉包函數的最大價值在於:我們可以在函數的外部(即子函數),直接讀取該函數的局部變量。
再仔細研究,就會發現f1()函數就如同一個“類”,而其定義的局部變量就如同該“類”的全局變量;而子函數f2()函數,則如同這個“類”的方法,可以直接使用這個“類”的全局變量n。神奇吧?
現在總算明白什么是閉包函數了,雖然其實現很神奇,但閉包函數有什么用?
1、緩存:最顯而易見的好處,就是可以實現數據緩存,我們可以把一個需要長期用到的變量設為閉包函數的局部變量,在子函數里面直接使用它。因此局部變量只定義初始化一次,但我們可以多次調用子函數並使用該變量。這比起我們在子函數中定義初始化變量,多次調用則多次初始化的做法,效率更高。閉包函數常見的一種用途就是,我們可以通過此實現計數功能。在閉包函數定義一個計數變量,而在子函數中對其進行++的操作。這樣每次調用閉包函數,計數變量就會加1。
function f1( ... ) local n = 0 function f2( ... ) n = n + 1 return n end return f2 end local count = f1() print(count()) --1 print(count()) --2 print(count()) --3 print(count()) --4 print(count()) --5
2、實現封裝:如同前面所說,閉包函數就如同一個“類”,只有在該閉包函數里的方法才可以使用其局部變量,閉包函數之外的方法是不能讀取其局部變量的。這就實現了面向對象的封裝性,更安全更可靠。