JS閉包函式和回撥函式
一、閉包
閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高階應用都要依靠閉包實現。閉包就是能夠讀取其他函式內部變數的函式。可以把閉包簡單理解成”定義在一個函式內部的函式”。
閉包有三個特性:
1.函式巢狀函式;
2.函式內部可以引用外部的引數和變數;
3.引數和變數不會被垃圾回收機制回收。
閉包是指有權訪問另一個函式作用域中的變數的函式,建立閉包的最常見的方式就是在一個函式內建立另一個函式,通過另一個函式訪問這個函式的區域性變數。使用閉包有一個優點,也是它的缺點,就是可以把區域性變數駐留在記憶體中,可以避免使用全域性變數。全域性變數在每個模組都可呼叫,這勢必將是災難性的。所以推薦使用私有的,封裝的區域性變數。一般函式執行完畢後,區域性活動物件就被銷燬,記憶體中僅僅儲存全域性作用域。但閉包的情況不同!
示例一:
//閉包就是一個函式的返回值為另外一個函式,在outer外部可以通過這個返回的函式訪問outer內的區域性變數.
function outer(){
var val = 0;
return function (){
val += 1;
document.write(val + "<br />");
};
}
var outObj = outer();
outObj();//1,執行val += 1後,val還在
outObj();//2
outObj = null;//val 被回收
var outObj1 = outer();
outObj1();//1
outObj1();//2
閉包會使變數始終儲存在記憶體中,如果不當使用會增大記憶體消耗(如果上例中定義很多outer(),則記憶體中會儲存很多val變數)。
javascript的垃圾回收原理:
(1)、在javascript中,如果一個物件不再被引用,那麼這個物件就會被GC回收;
(2)、如果兩個物件互相引用,而不再被第3者所引用,那麼這兩個互相引用的物件也會被回收。
那麼使用閉包有什麼好處呢?使用閉包的好處是:
1.希望一個變數長期駐紮在記憶體中
2.避免全域性變數的汙染
3.私有成員的存在
二、回撥
百度百科:回撥函式就是一個通過函式指標呼叫的函式。如果你把函式的指標(地址)作為引數傳遞給另一個函式,當這個指標被用為呼叫它所指向的函式時,我們就說這是回撥函式。回撥函式不是由該函式的實現方直接呼叫,而是在特定的事件或條件發生時由另外的一方呼叫的,用於對該事件或條件進行響應。
在JavaScript中,回撥函式具體的定義為:函式A作為引數(函式引用)傳遞到另一個函式B中,並且這個函式B執行函式A。我們就說函式A叫做回撥函式。如果沒有名稱(函式表示式),就叫做匿名回撥函式。
回撥函式原理:我現在出發,到了通知你”。這是一個非同步的流程,“我出發”這個過程中(函式執行),“你”可以去做任何事,“到了”(函式執行完畢)“通知你”(回撥)進行之後的流程。
示例一:
function doSomething(callback){
callback(1,2);
}
function numberAdd(a,b){
document.write(a+b);
}
doSomething(numberAdd);//3
示例二:
function Thing(name){
this.name = name;
}
//在Thing類里加入doSomething方法,這裡使用了構造器呼叫模式
Thing.prototype.doSomething = function(callback){
callback(this.name);
};
function showName(name){
document.write(name);
}
var t = new Thing("zhangsan");
t.doSomething(showName);//zhangsan
如果你有一個數字組成的陣列,你想寫個排序的公共方法,但是排序方式(從小到大或從大到小)是呼叫該排序方法的人決定。實現該排序方法可以用回撥來實現,當然你可以寫2個方法,一個是從小到大的排序,一個是從大到小的排序方法。回撥個人認為就是將決定權交給了實際業務開發工程師,由他來決定怎麼去處理,這種思路跟我們平常接觸的不同,有點不習慣,但是這種思路在非同步程式設計中特別能看出它的好處,不知道我這麼理解是否正確。下面示例程式碼就是回撥的典型使用場合:
var arr = [25,13,33,8,23,32];
Array.prototype.sort = function(callback){
var arr = this;
var i = 0;//i在這裡定義與在for迴圈的括號內(for(var i = 0; i < ...))定義是一樣的
for(; i < arr.length-1; i++){
var j = i + 1;
for(; j < arr.length;j++){
if(callback(arr[i],arr[j])){
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
};
//a-b>0表示陣列從小到大排序
arr.sort(function(a,b){
return a - b > 0;
});
document.write(arr.join(",") + "<br />");//8,13,23,25,32,33
//b-a>0表示陣列從大到小排序
arr.sort(function(a,b){
return b - a > 0;
});
document.write(arr.join(","));//33,32,25,23,13,8
回撥函式的使用場合:
資源載入:動態載入js檔案後執行回撥,載入iframe後執行回撥,ajax操作回撥,圖片載入完成執行回撥,AJAX等等。
DOM事件及Node.js事件基於回撥機制(Node.js回撥可能會出現多層回撥巢狀的問題)。
setTimeout的延遲時間為0,這個hack經常被用到,settimeout呼叫的函式其實就是一個callback的體現
鏈式呼叫:鏈式呼叫的時候,在賦值器(setter)方法中(或者本身沒有返回值的方法中)很容易實現鏈式呼叫,而取值器(getter)相對來說不好實現鏈式呼叫,因為你需要取值器返回你需要的資料而不是this指標,如果要實現鏈式方法,可以用回撥函式來實現setTimeout、setInterval的函式呼叫得到其返回值。由於兩個函式都是非同步的,即:他們的呼叫時序和程式的主流程是相對獨立的,所以沒有辦法在主體裡面等待它們的返回值,它們被開啟的時候程式也不會停下來等待,否則也就失去了setTimeout及setInterval的意義了,所以用return已經沒有意義,只能使用callback。callback的意義在於將timer執行的結果通知給代理函式進行及時處理。
相關文章
- 回撥函式 與 函式閉包函式
- PHP 回撥、匿名函式和閉包PHP函式
- [JS]回撥函式和回撥地獄JS函式
- JS—回撥函式JS函式
- js函式閉包JS函式
- JS之回撥函式(callback)JS函式
- js中的回撥函式JS函式
- js函式回撥錯誤JS函式
- 回撥函式函式
- 回撥函式,求積函式函式
- JS函式表示式——函式遞迴、閉包JS函式遞迴
- JS閉包函式概念JS函式
- js函式 函式自呼叫 返回函式的函式 (閉包)JS函式
- js 徹底理解回撥函式JS函式
- js 中的submit 回撥函式JSMIT函式
- 函式指標&回撥函式Callback函式指標
- JavaScript 回撥函式JavaScript函式
- JavaScript回撥函式JavaScript函式
- 動畫回撥函式動畫函式
- java回撥函式Java函式
- 回撥函式(CallBack)函式
- Python技法3:匿名函式、回撥函式和高階函式Python函式
- 函式指標之回撥函式和轉移表函式指標
- 回撥函式(c和指標)函式指標
- 回撥函式的作用函式
- TLS回撥函式(Note)TLS函式
- java 回撥函式示例Java函式
- Python回撥函式Python函式
- android回撥函式Android函式
- 函式回撥(C++)函式C++
- 函式閉包函式
- 閉包函式函式
- js中的函式巢狀和閉包JS函式巢狀
- 函式指標的重要用途——回撥函式函式指標
- 【知識點】inline函式、回撥函式、普通函式inline函式
- 關於 js 中的回撥函式 callbackJS函式
- 閉包函式(匿名函式)的理解函式
- C++回撥函式 用法C++函式