2014年12月4日 星期四

Javascript:宣告函數的方式



許多傳統的程式語言中,宣告一個函數,通常僅能藉由關鍵字如:private void Click(){....}來聲明並使用,但如果需要將函數作為參數傳給另一個函數,或者賦予給本地變數,甚至是作為一個返回值,是需要藉由pointer、delegate等特殊方式來達成,且較為複雜。
但在Javascript中就不一樣了,不但具有傳統函數的特點,也可以做到像變數一樣,作為參數的傳遞、變數的賦值、返回值等,甚至還可以作為"類"構造函數的作用,因此各種使用方式都有其優缺點在,需要加以了解後才能正確地使用,就以宣告方式來說,就有以下四種常見的宣告方式。

    ●函數宣告:function declaration(){...}
    ●函數運算式-匿名函數:var functionExpression = function(){....}
    ●函數運算式-具名函數:var namedFunctionExpression = function named(){....}
    ●Function類:var functionConstructor = new Function(...)

這些是常看到用來宣告函數的方法,但其中有些差異。
     一、函數宣告(Function Declaration)


function fn(){
     //content
}
使用這樣的方式來宣告函數,則同一個作用域內皆可訪問,不論宣告在調用之前或是調用之後,而這是因為在javascript執行前就被建立起來,而非動態產生,且藉由hoisting機制讓其提升到作用域最前面,即使寫代碼的時候在最後面也會被提升至最前面,在該領域的任何地方皆可存取,除此之外這種函數宣告方式又為具名函數,名稱為fn,採具名函數對於Debug是非常有幫助的。
fn();//doSomething
function fn(){
     console.log('doSomething');
}
fn();//doSomething
由於屬於靜態的關係,故缺點在於無法根據條件的判斷來決定function的內容。
 var flag = false;
    function fn1(){
        console.log('fn1')
    }
    if (flag) {
        function fn1(){
            console.log('fn1 and flag = true');
        }
    }
    fn1();
原本預期結果因flag = false故條件不成立,會是印出fn1,但實際結果卻是fn1 and flag = true,因此無法根據條件的判斷來決定function內容。

       二、函數運算式(Function Expressions)

可以宣告一個變數來動態產生一個function,但須注意的是在執行期間才被建立起來,因此在調用時得確保是否在調用之前就宣告,否則會發生「undefined is not a function」的錯誤,由於是動態產生,所以必須先產生才能調用。
fn();//undefined is not a function
var fn = function(){
     console.log('doSomething');
}
fn();//doSomething
這種宣告方式屬於動態宣告,故我們可以加入判斷來決定該function的內容,故可以得知結果為「fn1 and flag = true」。
   var flag = true;
   var fn1 = function(){
       console.log('fn1');
   };
    if (flag) {
        fn1 = function (){
            console.log('fn1 and flag = true');
        };
    }else{
        fn1 = function (){
            console.log('fn1 and flag = false');
        };
    }
    fn1();

      三、具名函數運算式(named function expressions,簡稱 NFE)

上面的宣告方式都是屬於匿名宣告,若想採用具名宣告可參考如下,對於Debug時較有幫助,且假設在function內又要呼叫自己的話可以採取具名方式,這樣一來可讀性較佳。

var result = function Fibonacci(n){
        return n === 1 ? n : n + Fibonacci(n - 1);
};
alert(Fibonacci(100))//這個變數在函數之外是看不到的
alert(result(100)); //1+...+100=5050

      四、函數關鍵字(Function Keyword)

直接使用Function關鍵字來建立函數物件,也就是使用new與建構子來建立函數,且不會建立任何的closure,在這個函數中只能存取全域的變數與該函數內部的變數,此外,每一次的執行都會進行parse的動作故效率較差。
var add = new Function('a','b','return a + b;')
console.log(add(5+3))//8
可以發現參數都是字串,這種建立方式充滿了危險性,尤其是如果參數來自使用者的輸入情況下更加危險。

沒有留言:

張貼留言