javascript 中函數參數的理解

 
一。理解參數


    ECMASCript 函數的參數與大多數其他語言中的函數的參數有所不同,ECMAScript函數不介意參數傳遞進來多少個參數,也不在乎傳進來參數是什麼數據類型。也就是說,即便你定義的函數接收兩個參數,在調用這個函數時也未必一定要傳遞兩個參數。可以傳遞一個,三個甚至不傳參數,二解釋器永遠不會有什麼怨言。之所以會這樣,原因是ECMASCript中的參數在內部是用一個數組來表示的。函數接收到始終都是這個數組,而不關心數組中包含哪些參數(如果有參數的話)。如果這個數組中不包含任何元素,無所謂; 如果包含多個元素,也沒問題。實際上,在函數體內可以通過arguments對象來訪問這個參數數組,從而獲取傳遞給函數的每一個參數。

    其實,arguments對象只是一個與數組類似(它並不是Array的實例),因爲可以使用方括號語法訪問它的每一個元素(即第一個元素師arguments[0],第二個元素師arguments[1],一此類推),使用length 屬性來確定傳遞進來多少個參數。在下面的(例1)中,sayHi()函數的第一個參數的名字叫name,而該參數的值也可以通過訪問argumens[0]來獲取,因此,那個函數也可以向下面(例2)這樣重寫,即不顯示地使用命名參數: 例1和例2的效果是一樣的。

      

 function sayHi(name, message) {
  alert("Hello "+ name + "," + message);
}   
例1
 
 function sayHi() {
  alert("Hello "+arguments[0] + "," +message);
}
例2
   例1重寫後的函數例2中不包含命名參數。雖然沒使用name和message標示符,但函數的功能依舊。這個事實說明ECMAScript函數的一個重要特點 : 命名參數只提供便利,但不是必需的。另外,在命名參數方面,其他語言可能需要事先創建一個函數簽名,而將來的調用必須與改簽名一致。但在ECMAScript中,沒有這些條條框框,解析器不會驗證命名參數。

   通過訪問arguments對象的length屬性可以獲知有多少個參數傳遞給了函數。下面這個函數會在每次調用時,輸出傳入其中的參數個數:

 

 function howManyArgs() {
  alert("輸出: "+arguments.length);
}
howManyArgs("string", 45); //輸出:2
howManyArgs();  //輸出:0
howManyArgs(23); //輸出:1

再有如下這個例子:

 function doAdd() {
   if (arguments.length == 1){
    alert(arguments[0]+10);
    } else if (arguments.length == 2) {
        alert(arguments[0]+arguments[1]);
  }
}

doAdd(10);    //輸出10
doAdd(20,20);  //輸出40

   另一個與參數相關的重要的方面,就是arguments對象可以與命名參數一起使用,如下例子所示:

 function doAdd(num1, num2) {
  if (arguments.length == 1) {
    alert(num1+10);
 } else if (arguments.length == 2) {
  alert(arguments[0]+num2);
 }
}
  在重寫後的這個doAdd()函數中,兩個命名參數都與arguments對象一起使用。由於num1的值與arguments[0]的值相同,因此他們可以互換使用,(當然,num2和arguments[1]也是如此).

  arguments的值與對應命名參數的值保持同步。例如:

  例3:

 function doAdd(num1,num2) {
    arguments[0] = 10;
    alert(num1 + arguments[1]);
}
doAdd(3,10);  //輸出 20
       每次執行這個doAdd()函數都會重寫第二個參數,將第二個參數的只修改爲10,。因爲arguments對象中的值會自動反映到對應的命名參數,所以修改arguments[0],也就修改了num1, 結果他們的值都變成了10,。不過,這並不是說讀取這兩個值會訪問相同的內存空間;他們的內存空間是獨立的,但他們的值會同步。但這種影響是單向的;修改命名參數不會改變arguments中對應的值。另外還要記住,如果只傳入一個參數,那麼爲arguments[1]設置的值不會反應到命名參數中。這是因爲arguments對象的長度是由傳入的參數個數決定的,不是由定義函數時的命名參數的個數決定的。

     關於參數還要記住最後一點: 沒有傳遞值的命名參數將自動被賦予undefined值、這就跟定義了變量但沒有初始化一樣。

     嚴格模式對如何使用arguments對象做出了一些限制,首先,向前面(例3)中的那樣賦值會變得無效,也就是說,即使把arguments[0] = 10, num1的值仍然還是undefined. 其次,重寫arguments的值會導致語法錯誤。

     ECMAScript中的所有參數傳遞的都是值,不可能通過引用傳遞參數.

   

.ECMAScript 函數沒有重載

         ECMAScript函數不能像傳統意義上那樣實現重載。而在其他語言(如:java)中,可以爲一個函數編寫兩個定義,只要這兩定義的簽名(接受的參數的類型和數量)不同即可。如前所述,ECMAScript函數沒有簽名,因爲其參數是由包含零個或多個值的數組表示的。(其實也可這麼理解,函數的參數的個數或類型是不確定的,由傳入的參數個數決定的,所以當傳入實參時解釋器不知道該調用哪個重載函數)而沒有函數簽名,真正的重載是不可能做到的。

      如果在ECMAScript中定義了兩個名字相同的函數,則該名字只屬於後定義的函數,請看下面的例子:

 

 function addSomeNumber(num) {
 return num+100;
}
function addSomeNumber(num) {
 return num+200;
}
var result = addSomeNumber(100);  //輸出: 300

   在此,函數addSomeNumber(num) 被定義兩次。由於後定義的函數覆蓋了先定義的函數,因此當調用函數時,返回的結果就是300.

 

原文來自 :JavaScript 高級程序設計(第三版)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章