天天看點

《JavaScript進階程式設計》學習筆記之JavaScript函數介紹

JavaScript函數介紹

函數對任何語言來說都是一個核心的概念。通過函數可以封裝任意多條語句,而且可以在任何地方、任何時候調用執行。ECMAScrip中的函數使用function關鍵字來聲明,後跟一組參數以及函數體。函數的基本文法如下所示:

function functionName(arg0, arg1, ..., argN) {
  statement;
}
           

在含有return語句的函數中,函數會在執行完return語句之後停止并立即退出。是以,位于return語句之後的任何代碼永遠都不會執行。例如:

function sum(num1, num2){
  return num1 + num2;
  alert("Hello World"); //永遠不會執行
}
           

在上面的例子中,由于調用alert()函數的語句位于return語句之後,是以永遠不會顯示警示框,

當然,一個函數中也可以包含多個return語句,如下例所示:

function diff(num1, num2){
  if(num1 < num2){
    return(num2 - num1);
  }else{
    return(num1 - num2);
  }
}
           

另外,return語句也可以不大有任何傳回值。在這種情況下,函數在停止執行後将傳回undefined值。這種用法一般用在需要提前停止函數執行而又不需要傳回值的情況下。比如在下面的例子中,就不會顯示警示框:

function sayHi(name, message){
  return;
  alert("Hello " + name + "," + message); //永遠都不會調用
}
           

推薦的做法是要麼讓函數始終都傳回一個值,要麼永遠都不要傳回值,否則,如果函數有時傳回值,有時候不傳回值,會調式代碼帶來不便。

了解參數

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

其實,arguments對象隻是與數組類似(它并不是Array的執行個體),因為可以使用方括号文法通路它的每一個元素(即第一個元素是arguments[0],第二個元素是arguments[1],以此類推),使用length屬性來确定傳遞進來多少個參數。在前面的例子中,sayHi()函數的第一個參數的名字叫name,而該參數的值也可以通過通路arguments[0]來擷取。是以,該函數也可以像像下面這樣重寫,即不顯示地使用命名參數:

function sayHi(){
  alert("Hello " + arguments[0] + "," + arguments[1]);
}
sayHi("Wangwei", "how are you today?");
           

這個重寫後的函數中不包含命名的參數,雖然沒有使用name和message辨別符,但函數的功能依舊。這個事實說明了ECMAScript函數的一個重要特點:命名的參數隻提供便利,但不是必須的。另外,在命名參數方面,其他語言可能需要事先建立一個函數簽名,而将來的調用必須與該簽名一緻。但在ECMAScript中,沒有這些條條框框,解析器不會驗證命名參數。

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

function howManyArgs() {
  alert(arguments.length);
}
howManyArgs("string", 45); //2
howManyArgs();             //0
howManyArgs(12);           //1
           

執行以上代碼會依次出現3個警示框,分别顯示2、0和1。由此可見,開發人員可以利用這一點讓函數能夠接收任意個參數并分别實作适當的功能。如下面的例子:

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

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

function doAdd(num1, num2) {
  if(arguments.length == 1) {
    alert(num1 +10);
  }else if(arguments.length == 2){
    alert(arguments[0] + num2);
  }
}
doAdd(10); //20
doAdd(30, 20); //50
           

在重寫後的這個doAdd()函數中,兩個命名參數都與arguments對象一起使用,由于num1的值與arguments[0]的值相同,是以它們可以互換使用(當然,num2和arguments[1]的值也是如此)。

關于參數還應記住最後一點:沒有傳遞值的命名參數将自動被賦予undefined值,這就跟定義了變量但又沒有初始化一樣。例如,如果隻給doAdd()函數傳遞了一個參數,則num2中就會儲存undefined值。ECMAScript中的所有參數傳遞的都是值,不可能通過引用傳遞參數。

繼續閱讀