chapter 3 基本概念(3.7 函數)

《JavaScript高級程序設計》第三版 筆記

3.7 函數

通過函數可以封裝任意多條語句。
可以在任何地方、任何時候調用執行。(通過函數名來調用,後面加上一對圓括號和參數。多個參數以逗號隔開。)
使用 function 關鍵字來聲明,後跟一組參數以及函數體。

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

return
函數在定義時不必指定是否返回值。
任何函數在任何時候都可以通過 return 語句後跟要返回的值來實現返回值。
example:

function sum(num1,num2){
  return num1 + num2;
}

函數會在執行完 return 語句之後停止並立即退出,位於 return 語句之後的任何代碼都永遠不會執行。
example:

function sum(num1,num2){
      return num1 + num2;
      console.log("hello");  //不會被執行
    }
    console.log(sum(3,5));  //8
function sum(num1,num2){
      return num1 + num2;
      return num1 - num2;  //不會被執行
    }
    console.log(sum(3,5));  //8

一個函數中可以包含多個 return 語句
example:

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

return 語句也可以不帶有任何返回值。這種情況下函數停止執行後將返回 undefined 值
這種用法一般用在需要提前停止函數執行而又不需要返回值的情況下。
example:

function sayHi(name,message){
  return;
  alert("hello" + name + "," + message);  //永遠不會調用
}
console.log(sayHi("jim","haha"));  //undefined

*推薦的做法是要麼讓函數始終都返回一個值,要麼永遠都不要返回值;
否則有時返回值,有時不返回值會給調試代碼帶來不便。

*嚴格模式對函數有一些限制:
1.不能把函數名命名爲 eval 或 arguments;
2.不能把參數命名爲 eval 或 arguments;
3.不能出現兩個命名參數同名的情況。
如果發生以上情況,就會導致語法錯誤,代碼無法執行。

3.7.1 理解參數

ECMAScript 中的參數在內部是用一個數組來表示的,在函數體內可以通過 arguments 對象來訪問這個參數數組;
函數接收到的始終都是這個數組,而不關心數組中包含哪些參數(如果有參數的話)
這意味着:
1.函數可以傳遞任意個數的參數,並且什麼數據類型都可以。
2.即使定義的函數只接收兩個參數,調用時也未必一定要傳遞兩個參數,不傳參或傳遞多個參數解析器也不會有怨言。

arguments 對象並不是 Array 的實例,它只是與數組類似
可以使用方括號語法訪問它的每一個元素(例如 arguments[0]);

不顯式的使用命名參數
example:
這個函數中不包含命名的參數。雖然沒有使用 name 和 message 標識符,但函數的功能依舊;
命名的參數只提供便利,但不是必需的。
arguments 對象可以與命名參數一起使用。(例如第一個參數和 arguments[0] 的值相同,因此可以互換使用。

function sayHi(){
  alert("hello" + arguments[0] + "," + arguments[1]);
}

使用 length 屬性確定傳遞進來多少參數。
example:

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

可以利用這一點讓函數能夠接收任意個參數並分別實現適當的功能。
example:
(這個特性算不上完美的重載,但可以彌補這一缺憾。)

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 對象中的值會自動反映到對應的命名參數(例如修改了 arguments[0] ,也就修改了第一個命名參數的值);
但讀取這兩個值並不會訪問相同的內存空間,它們的值會同步,但內存空間是獨立的;
這種影響是單向的,修改命名參數不會改變 arguments 中對應的值。

arguments 對象的長度是由 傳入 的參數個數決定的,不是由定義函數時命名參數的個數決定的
沒有傳遞值的命名參數將自動被賦予 undefined 值,這就跟定義了變量但又沒有初始化一樣。

嚴格模式下:
命名參數未賦值的情況下,在函數中例如爲 arguments[0] 賦值,第一個命名參數的值仍然是 undefined ;
其次,重寫 arguments 的值會導致語法錯誤(代碼將不會執行)。

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

3.7.2 沒有重載

ECMAScript 函數不能像傳統意義上那樣實現重載。
在其他語言(例如Java)中,可以爲一個函數編寫兩個定義,只要這兩個定義的簽名(接受的參數的類型和數量)不同即可。
ECMAScript 函數沒有簽名,因爲其參數是由包含零或多個值的數組來表示的。
沒有函數簽名,真正的重載是不可能做到的。

如果在 ECMAScript 中定義了兩個名字相同的函數,則該名字只屬於後定義的函數(後定義的函數覆蓋了先定義的函數) 。
example:

function addSomeNumber(num) {
  return num + 100;
}
function addSomeNumber(num) {
  return num + 200;
}
console.log(addSomeNumber(100));  //300

*例如上一節,通過檢查傳入函數中參數的類型和數量並作出不同的反應,可以模仿方法的重載。

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