函式

函式是可重複使用的模組化陳述式區塊,用於執行一組相關任務,例如根據提供給函式的引數計算及傳回值。和所有非原始值一樣,函式是物件。這些物件是不重複的物件,可供呼叫來執行程式碼、以引數形式傳遞資料,以及return值。

系統會將函式視為「第一個類別」物件,也就是說,即使函式有獨特的行為,可以在與任何其他 JavaScript 物件相同的結構定義中使用這些函式。舉例來說,函式可以指派給變數、做為引數傳遞至其他函式,並由其他函式傳回。

function myFunction() {
   console.log( "This is my function." );
};

定義為物件屬性的函式通常稱為「方法」。和使用 var 宣告的變數一樣,在包含函式外建立的函式宣告會以方法的形式加入全域物件中。

函式宣告

函式宣告 (也稱為「函式陳述式」或「函式定義」) 會建立已命名函式,可以在其包含範圍的其他位置叫用。函式宣告由 function 關鍵字後方依序包含 ID、括號括住的參數清單,以及名為「函式主體」的區塊陳述式。您經常會發現結尾不是半形分號的函式宣告。由於函式宣告是陳述式,結尾分號可由 ASI 推論。

function myFunction() {
   console.log( "This is my function." );
};

myFunction();
> "This is my function."

由於 JavaScript 早期設計決定的保留,函式宣告必須遵循與使用 var 宣告的變數相同的舊版「提升」行為,意即函式宣告提升至範圍頂端,而在宣告前可以呼叫該範圍,無論該範圍是否受嚴格模式規範:

"use strict";
{
    myFunction();
    function myFunction() {
        console.log( "This is my function." );
    };
}
> "This is my function."

嚴格模式以外,函式宣告會使用 JavaScript 的舊版「範圍限定」行為,表示函式宣告的範圍僅限最接近圍繞的函式:

function myFunction() {
    function myNestedFunction() {
        console.log( "This is my nested function." );
    }
    myNestedFunction();
};

myFunction();
> "This is my nested function."

myNestedFunction();
>Uncaught ReferenceError: myNestedFunction is not defined

嚴格模式中,函式宣告的範圍是以 letconst 宣告的變數一樣,限定為最接近的封閉區塊:

"use strict";
{
    function myFunction() {
        console.log( "This is my function." );
    };
}

myFunction();
> Uncaught ReferenceError: myFunction is not defined

函式呼叫

與變數一樣,宣告函式時使用的 ID 作為值的符號名稱。單獨透過 ID 參照函式只會傳回函式物件,系統不會執行其中含有的函式:

function myFunction() {
   console.log( "This is my function." );
};

myFunction;
> myFunction() {
   console.log( "This is my function." );
}

如要在函式主體中執行程式碼,請在函式名稱後方加上一組相符的括號呼叫 (或「叫用」):

function myFunction() {
    console.log( "My function has been executed." );
}

myFunction();
> "My function has been executed."

函式定義中的參數可做為預留位置變數,以供呼叫函式時傳遞至函式主體的值。呼叫函式時,括號中的值皆為「引數」(雖然某些說明文件可能會用「引數」描述引數和參數):

function myFunction( myParameter ) {
   console.log( `The value is: ${ myParameter }.` );
};

myFunction( "this string" );
> "The value is: this string."

如果省略預期的引數,產生的參數會包含 undefined 值,因為該參數已宣告給函式主體,但未使用值初始化:

function myFunction( myParameter ) {
   console.log( `The value is: ${ myParameter }.` );
};

myFunction();
> "The value is: undefined."

如要設定預設參數值,初始化方式與初始化變數相同:指派運算子 (=) 後面加上值。如果您之後指定該函式的引數,新值會覆寫預設值:

function myFunction( myParameter = "omitted" ) {
   console.log( `The value is: ${ myParameter }.` );
};

myFunction( "this string" );
> "The value is: this string."

myFunction();
> "The value is: omitted."

非箭頭函式的主體也可以存取含有零索引且陣列arguments 物件,其中包含任何做為引數傳遞的值,無論函式定義是否指定參數:

function myFunction() {
   console.log( arguments );
};

myFunction( 3, true, "My string" );
> Arguments { 0: 3, 1: true, 2: "My string", … }

判斷函式

arguments 物件可讓您建立基本的病毒函式,可接受可變數數量的引數:

function myFunction() {
    let result = "";
    for (let i = 0; i < arguments.length; i++) {
        result += arguments[i] + " - ";
    }
    console.log( result );
};

myFunction( "My first string", "My second string", "my third string" );\
> "My first string - My second string - my third string - "

不過,現代 JavaScript 開發時很少用到這種變化函式的方法。較常見的做法是使用較新式且可讀取的重設參數語法。系統會建立已初始化的已命名參數,並將其初始化為陣列,其中包含明確指定以外的任何引數:

function myFunction( mySeparator, ...myStrings ) {
  console.log( myStrings.join( mySeparator ) );
};

myFunction( " - ", "My first string", "My second string", "my third string" );
> "My first string - My second string - my third string"

parameter 繫結不同,休息參數語法可與箭頭函式參數搭配使用:

function myOuterFunction() {
    let myInnerArrowFunction = ( ...myParams ) => {
        console.log( myParams[ 0 ] );
    }
    myInnerArrowFunction( true );
};

myOuterFunction( false );
> true

let myArrowFunction = ( ...myParams ) => {
    console.log( myParams[ 0 ] );
};

myArrowFunction( true );
> true`
``