前些陣子寫了幾篇關於回調和閉包的博文,感覺自己都是似懂非懂,最近在項目中又碰到了類似的情況,故在此咱們來重彈js中的回調與閉包。
先說說回調:
百度百科:
回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用為調用它所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。
在JavaScript中:回調函數的具體定義為: 函數A作為參數(函數引用)傳遞到另一個函數B中,並且這個函數B執行函數A。我們就說函數A叫做回調函數。如果沒有名稱(函數表達式),就叫做匿名回調函數。
在js中,AJAX的異步加載時用到了回調函數的,但其實回調不僅僅是用在異步中,同步操作也可以使用:
同步的場景: 即在每個函數執行完成后調用另一個函數,下面列出網上的一些代碼以作例子:
var func1=function(callback){ //do something. (callback && typeof(callback) === "function") && callback(); //檢測函數存在且是一個函數然后再調用 } func1(func2); var func2=function(){ }
異步的情況的或就不用多說了,我們在AJAX中都是用的不要不要的了。
什么時候使用回調函數呢,這里列出一些前人總結的經驗:
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
閉包(似乎是談JavaScript漏不掉的問題):
什么是閉包?還是那句話: 首先,他是一個函數,其次,他能訪問包含他的外部函數的變量,粗糙點理解,就是:定義在一個函數內部的函數,但是呢,這個里面的函數他訪問了他外面的那個函數的變量。這對於外面函數來說,就形成了閉包,
官方解釋:
來源:知乎
Javascript 中,每個函數都有一個與之相關聯的作用域鏈。每次調用 JavaScript 函數的時候,都會為之創建一個新的對象用來保存局部變量,並把這個對象添加至作用域鏈中。當函數返回時,再將這個對象刪除,此對象會被當做垃圾回收。但如果這個函數定義了嵌套的函數,並將它存儲在某處的屬性里,就意味着有了一個外部引用指向這個嵌套的函數。它就不會被當作垃圾回收,它所指向的變量綁定對象同樣不會被回收
來源:JavaScript秘密花園
閉包是 JavaScript 一個非常重要的特性,這意味着當前作用域總是能夠訪問外部作用域中的變量。 因為 函數 是 JavaScript 中唯一擁有自身作用域的結構,因此閉包的創建依賴於函數。
舉個栗子:
function foo(x) { var tmp = 3; return function (y) { alert(x + y + (++tmp)); } } var bar = foo(2); // bar 現在是一個閉包 bar(10); //16
此時,在foo函數中已經形成了一個閉包,這就意味着,只要bar函不死,垃圾回收機制就不敢去動foo函數,而此時,我們的bar函數所指向的那個匿名函數就可以一直去訪問那個tmp和x,且,注意了!注意了!:::每次調用,都會得到上一次被自增了以后的tmp
bar(10); //16 第一次調用
bar(10); //17 第二次調用
同時,我們強調:
外部函數不是必需的。通過訪問外部變量,一個閉包可以維持(keep alive)這些變量。在內部函數和外部函數的例子中,外部函數可以創建局部變量,並且最終退出;但是,如果任何一個或多個內部函數在它退出后卻沒有退出,那么內部函數就維持了外部函數的局部數據。
一個典型的例子就是全局變量的使用。
記得曾經有人說過:
In computer science, a closure is a function together with a referencing environment for the nonlocal names (free variables) of that function.
仁者見仁智者見智啦!!!
在JAVA中,我們知道他有一個叫數據隱藏的特性: 那么,JavaScript中的閉包,或許為我們敞開了大門:
來看看網上的例子:
似曾相識!!!有木有:
OK THAT’S IT!!!