首頁 >web前端 >js教程 >js中匿名函數的建立與呼叫方法分析_javascript技巧

js中匿名函數的建立與呼叫方法分析_javascript技巧

WBOY
WBOY原創
2016-05-16 16:25:361400瀏覽

本文實例分析了js中匿名函數的創建與呼叫方法。分享給大家供大家參考。具體實作方法如下:

匿名函數就是沒有名字的函數了,也叫閉包函數(closures),允許 暫時建立一個沒有指定名稱的函數。最常用作回呼函數(callback)參數的值,很多新手朋友對於匿名函數不了解。這裡就來分析一下。

function 函數名稱(參數列表){函數體;}

如果是建立匿名函數,那應該是:
function(){函數體;}

因為是匿名函數,所以一般也不會有參數傳給他。

為什麼要建立匿名函數呢?在什麼情況下會使用到匿名函數。匿名函數主要有兩種常用的場景,一是回呼函數,二是直接執行函數。

回呼函數,像ajax的非同步操作,就需要回呼函數。這裡就不詳解。關於直接執行函數,我看一個例子就明白了:

複製程式碼 程式碼如下:

在上面這段程式碼中,會順序輸出兩個alert框。第一個alert框內容為b,第二個為a。大家看到什麼好處了嗎?對的,使用函數直接執行可以限定變數的作用域,使不同腳本的相同變數可以共存。

下面,我們先初步了解一下和匿名函數相關的概念。

函數宣告(function 語句),要使用一個函數,我們就得先宣告它的存在。而我們最常用的方式就是使用function 語句來定義一個函數,如:

複製程式碼 程式碼如下:
function abc(){
// code to process
}
function abc(){ // code to process }

當然,你的函數也可以是帶參數的,甚至是帶回傳值的。

複製程式碼 程式碼如下:
view plaincopy to clipboardprint?
function abc(x,y){
return x y;
}
function abc(x,y){ return x y; }

但是,無論你怎麼去定義你的函數,JS 解譯器都會把它翻譯成一個Function 物件。例如,你在定義上面的其中一個範例的函數號,再輸入如下程式碼:

複製程式碼 程式碼如下:
alert(typeof abc);// "function"

你的瀏覽器就會跳出提示框,提示你abc 是一個Function 物件。那麼Function 物件究竟是什麼呢?

Function 物件


Function 物件是JavaScript 裡面的固有對象,所有的函數其實都是一個Function 物件。我們先看看,Function 物件能不能直接運用建構子來建立一個新的函數呢?答案是肯定的。例如:

程式碼如下:

var abc = new Function("x","y","re​​turn x* y;");
alert(abc(2,3)); // "6"
相信大家現在對如何宣告一個函數應該是有所了解了。那什麼才是匿名函數呢?

宣告匿名函數


顧名思義,匿名函數就是沒有實際名字的函數。例如,我們把上面的例子中,函數的名字去掉,再判斷他是不是一個函數:

程式碼如下:

alert(typeof function(){});// "function"
alert(typeof function(){});// "function"
alert(typeof function(x,y){return x y;});// "function"
alert(typeof new Function("x","y","re​​turn x*y;"))// "function"
alert(typeof function(){});// "function"
alert(typeof function(x,y){return x y;});// "function" alert(typeof new Function("x","y","re​​turn x*y;"))// "function"

我們可以很容易地看到,它們全都是Function 對象,換言之,他們都是函數,但是他們都有一個特點—— 沒有名字。所以我們把他們稱為「 匿名函數」 。然而,正因為他們沒有「 名字」 ,我們也沒有辦法找到他們。這就引申瞭如何去呼叫一個匿名函數的問題了。

匿名函數的呼叫

要呼叫一個函數,我們必須要有方法定位它,引用它。所以,我們會需要幫它找一個名字。例如:

複製程式碼 程式碼如下:
var abc=function(x,y){
return x y;
}
alert(abc(2,3)); // "5"

上面的運算其實等於換個方式去定義函數,這種用法是我們比較常遇到的。例如我們在設定一個DOM 元素事件處理函數的時候,我們通常不會為他們定名字,而是賦予它的對應事件引用一個匿名函數。

匿名函數的呼叫其實還有一種做法,也就是我們看到的jQuery 片段- 使用() 將匿名函數括起來,然後後面再加一對小括號(包含參數列表)。我們再看一下以下例子:

複製程式碼 程式碼如下:
alert((function(x,y){return x y;})(2, 3));// "5"
alert((new Function("x","y","re​​turn x*y;"))(2,3));// "6"

很多人或許會奇怪,為什麼這種方法能成功呼叫呢?覺得這個應用奇怪的人就看一下我以下這段解釋吧。

大家知道小括號的作用嗎?小括號能把我們的表達式組合分塊,而且每一塊,也就是每一對小括號,都有一個回傳值。這個回傳值其實也就是小括號中表達式的回傳值。所以,當我們用一對小括號把匿名函數括起來的時候,實際上小括號對回傳的,就是一個匿名函數的Function 物件。因此,小括號對加上匿名函數就如同有名字的函數般被我們取得它的引用位置了。所以如果在這個引用變數後面再加上參數列表,就會實作普通函數的呼叫形式。

不知道以上的文字表述大家能不能看明白,如果還是理解不了的話,再看一下以下的程式碼試試看。

複製程式碼 程式碼如下:
var abc=function(x,y){return x y;};// 把匿名函數物件賦給abc
// abc 的constructor 就跟匿名函數的constructor 一樣了。也就是說,兩個函數的實作是一樣的。
alert((abc).constructor==(function(x,y){return x y;}).constructor);

PS :constructor 是指建立物件的函數。也就是函數物件所代表的函數體。
總之,將其(被小括號包含的匿名函數)理解為括號表達式返回的函數對象,然後就可以對這個函數對像作正常的參數列表調用了。 (前面這裡犯了個錯誤,只有函數表達式還是不能直接呼叫函數的,去掉匿名函數括號必須要伴隨將表達式賦值。也就是(function(){alert(1)})() 應該是與a =function(){alert(1)}() 等價,不能連a= 都去掉。

閉包

閉包是什麼?閉包是指某種程式語言中的程式碼區塊允許一級函數存在並且在一級函數中所定義的自由變數能不被釋放,直到一級函數被釋放前,一級函數外也能應用這些未釋放的自由變數。

怎樣?看得一頭冒汗吧…… 沒事,我也是(雖然是我是了解的,只是表達能力的問題)。讓我們換個更簡單的方法說明:閉包,其實是一種語言特性,它是指的是程式設計語言中,允許將函數看作對象,然後能像在對像中的操作般在函數中定義實例(局部)變量,而這些變數能在函數中保存到函數的實例物件銷毀為止,其它程式碼區塊能透過某種方式取得這些實例(局部)變數的值並進行應用擴展。

不知道這麼再解釋後會否更加清晰,如果還是不明白,那麼我們再簡化一下:閉包,其實就是指程式語言中能讓程式碼呼叫已執行的函數中所定義的局部變數。

現在我們來看一個例子:


複製程式碼 程式碼如下:
var abc=function(y){
var x=y;// 這個是局部變數
return function(){
alert(x );// 就是這裡呼叫了閉包特性中的一級函數局部變數的x ,並對它進行操作
alert(y--);// 引用的參數變數也是自由變數
}}(5);// 初始化
abc();// "5" "5"
abc();// "6" "4"
abc();// "7" "3"
alert(x);// 報錯誤! “x” 未定義!

看到這裡,你能判斷究竟jQuery 的那個程式碼片段是否閉包了嗎?

以我的理解來說吧。是否應用了閉包特性,必須確定該段程式碼有沒有最重要的要素:未銷毀的局部變數。那麼很顯然,沒有任何實現的匿名函數不可能應用了閉包特性。但如果匿名函式裡面有實作呢?那也得確定它的實作中有沒有 用到那些未銷毀的局部變數。所以如果問你那個開篇中的jQuery 程式碼片段是應用了JS 裡的什麼特性?那麼它只是匿名函數與匿名函數的呼叫而已。但是,它 隱含了閉包的特性,隨時可以實現閉包應用。

最常見的用法:

複製程式碼 程式碼如下:
(function() {
alert('water');
})();

當然也可以帶參數:
複製程式碼 程式碼如下:
(function(o) {
alert(o);
})('water');

想用匿名函數的鍊式呼叫?很簡單:
複製程式碼 程式碼如下:
(function(o) {
alert(o);
return arguments.callee;
})('water')('down');

常見的匿名函數都知道了,看看不常見的:
複製程式碼 程式碼如下:
~(function(){
alert('water');
})();//寫法有點酷~
 
void function(){
alert('water');
}();//據說效率最高~
 
function(){
alert('water');
}();
 
-function(){
alert('water');
}();
 
~function(){
alert('water');
}();
 
!function(){
alert('water');
}();
 
(function(){
alert('water');
}());//有點強制執行的味道~

希望本文所述對大家的javascript程式設計有所幫助。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn