JavaScript進階系列01,函式的宣告,函式引數,函式閉包

Darren Ji發表於2014-10-03

本篇主要體驗JavaScript函式的宣告、函式引數以及函式閉包。

 

□ 函式的宣告

※ 宣告全域性函式

通常這樣宣告函式:

        function doSth() {
            alert("可以在任何時候呼叫我");
        }

通過這種方式宣告的函式屬於Window物件,可以在任何地方呼叫,即在doSth方法的之前和之後都可以呼叫。

 

可以在doSth方法之前呼叫:

        doSth();
        function doSth() {
            alert("可以在任何時候呼叫我");
        }

 

可以在doSth方法之後呼叫:

        function doSth() {
            alert("可以在任何時候呼叫我");
        }
        doSth();

 

※ 把函式賦值給變數

        var doSomething = function() {
            alert("只能在宣告我之後再呼叫");
        };

 

不可以在doSomething方法之前呼叫:

        doSomething();
        var doSomething = function() {
            alert("只能在宣告我之後再呼叫");
        };

以上,報"undefined funciton ..."錯。

 

可以在doSomething方法之後呼叫:  

        var doSomething = function() {
            alert("只能在宣告我之後再呼叫");
        };
        doSomething();   
 

□ 函式引數

※ 即使宣告的函式沒有引數,也可以在呼叫時傳入引數

        doSth("你好");
        function doSth() {
            alert(arguments[0]);
        }

輸出結果:你好

 

※ arguments.callee屬性表示函式引用

        doSth("你好");
        function doSth() {
            alert(arguments.callee);
        }

1
以上,在函式內部使用arguments.callee屬性表示的是函式本身。

 

※ arguments.callee()方法遞迴呼叫函式

        doSth();
        function doSth() {
            alert("你好");
            arguments.callee();          
        }
輸出結果:不斷顯示"你好"    


□ 函式閉包

※ 閉包的形成

先看下面程式碼:

        function doSth(val) {
            return function() {
                alert(val);
            };
        }
        var fn = doSth("hello");
        fn();

輸出結果:hello

在doSth方法內部返回一個匿名函式,通過fn()執行匿名函式,把doSth方法的引數變數val列印了出來。在這裡,doSth方法內部的匿名函式被稱作"閉包"。換句話說,我們在記憶體上建立了一個匿名物件。   


※ 閉包的釋放

如果在呼叫fn方法之後,通過fn=null,把fn設定為null,首先匿名函式所佔記憶體被釋放,接著,由於變數val不再被引用,val所佔記憶體被釋放,最後釋放doSth所佔記憶體。

 

※ 過多的"閉包"會增加記憶體開銷

        function doSth(val) {
            return function() {
                alert(val);
            };
        }
        var fn = doSth("hello");
        var fn2 = doSth("hello2");
        fn();
        fn2();
        fn();

輸出結果:依次顯示hello, hello2, hello

無論是呼叫fn方法,還是fn2方法,都會在記憶體上建立匿名物件,消耗更多的記憶體。

 

※ 使用"閉包"建立module

舉例:宣告一個函式用來建立唯一的ID

        var i = 0;
        function CreateUniqueName() {
            var name = "name" + i;
            i = i + 1;
            return name;
        }
        var name1 = CreateUniqueName();
        var name2 = CreateUniqueName();
        alert(name1 + " " + name2);

輸出結果:name0 name1

 

以上存在幾個問題:
1、建立的函式不是全域性的,只能在當前頁使用
2、變數i和方法CreateUnqiueName都是全域性的,這可能會造成與第三方程式碼的名稱衝突 

 

所以,我們應該把以上的邏輯寫成全域性,並做成一個module,並自定義名稱。

       var myUtilty = (function() {
           var i = 0;
           return {
               CreateUniqueName: function() {
                   var name = "name" + i;
                   i = i + 1;
                   return name;
               }
           };
        }());
        
        var name1 = myUtilty.CreateUniqueName();
        var name2 = myUtilty.CreateUniqueName();
        alert(name1 + " " + name2);

○ (function(){}());被稱作是匿名、自觸發函式,返回一個json物件,並且只執行一次
○ 正因為匿名、自觸發函式只被執行一次,所有全域性只有一個myUtitly物件,不會過多消耗記憶體
○ json物件的鍵CreateUniqueName對應一個匿名方法  
○ 匿名、自觸發函式可以被看作是全域性的、唯一的"閉包" 

 

“JavaScript進階系列”包括:

JavaScript進階系列01,函式的宣告,函式引數,函式閉包

JavaScript進階系列02,函式作為引數以及在陣列中的應用

JavaScript進階系列03,通過硬編碼、工廠模式、建構函式建立JavaScript物件

JavaScript進階系列04,函式引數個數不確定情況下的解決方案

JavaScript進階系列05,事件的執行時機, 使用addEventListener為元素同時註冊多個事件,事件引數

JavaScript進階系列06,事件委託

JavaScript進階系列07,滑鼠事件

 

相關文章