作為變數的功能

正常的函式宣告如下所示:

function foo(){
}

這樣定義的函式可以通過其名稱從其上下文中的任何位置訪問。但有時候處理像物件引用這樣的函式引用會很有用。例如,你可以根據某些條件將物件分配給變數,然後從一個或另一個物件中檢索屬性:

var name = 'Cameron';
var spouse;

if ( name === 'Taylor' ) spouse = { name: 'Jordan' };
else if ( name === 'Cameron' ) spouse = { name: 'Casey' };

var spouseName = spouse.name;

在 JavaScript 中,你可以使用函式執行相同的操作:

// Example 1
var hashAlgorithm = 'sha1';
var hash;

if ( hashAlgorithm === 'sha1' ) hash = function(value){ /*...*/ };
else if ( hashAlgorithm === 'md5' ) hash = function(value){ /*...*/ };

hash('Fred');

在上面的例子中,hash 是一個普通變數。它被賦予對函式的引用,之後可以使用括號呼叫它引用的函式,就像正常的函式宣告一樣。

上面的示例引用了匿名函式…沒有自己名稱的函式。你還可以使用變數來引用命名函式。上面的例子可以這樣重寫:

// Example 2
var hashAlgorithm = 'sha1';
var hash;

if ( hashAlgorithm === 'sha1' ) hash = sha1Hash;
else if ( hashAlgorithm === 'md5' ) hash = md5Hash;

hash('Fred');

function md5Hash(value){
    // ...
}

function sha1Hash(value){
    // ...
}

或者,你可以從物件屬性分配函式引用:

// Example 3
var hashAlgorithms = {
    sha1: function(value) { /**/ },
    md5: function(value) { /**/ }
};

var hashAlgorithm = 'sha1';
var hash;

if ( hashAlgorithm === 'sha1' ) hash = hashAlgorithms.sha1;
else if ( hashAlgorithm === 'md5' ) hash = hashAlgorithms.md5;

hash('Fred');

你可以通過省略括號將對一個變數所持有的函式的引用分配給另一個變數。這可能導致一個容易犯的錯誤:嘗試將函式的返回值分配給另一個變數,但意外地將該引用分配給該函式。

// Example 4
var a = getValue;
var b = a; // b is now a reference to getValue.
var c = b(); // b is invoked, so c now holds the value returned by getValue (41)

function getValue(){
    return 41;
}

對函式的引用與任何其他值類似。如你所見,可以將引用分配給變數,然後可以將該變數的引用值分配給其他變數。你可以像傳遞任何其他值一樣傳遞對函式的引用,包括將對函式的引用作為另一個函式的返回值傳遞。例如:

// Example 5
// getHashingFunction returns a function, which is assigned
// to hash for later use:
var hash = getHashingFunction( 'sha1' );
// ...
hash('Fred');

// return the function corresponding to the given algorithmName
function getHashingFunction( algorithmName ){
    // return a reference to an anonymous function
    if (algorithmName === 'sha1') return function(value){ /**/ };
    // return a reference to a declared function
    else if (algorithmName === 'md5') return md5;
}

function md5Hash(value){
    // ...
}

你無需為變數分配函式引用即可呼叫它。這個示例構建示例 5,將呼叫 getHashingFunction,然後立即呼叫返回的函式並將其返回值傳遞給 hashedValue。

// Example 6
var hashedValue = getHashingFunction( 'sha1' )( 'Fred' );

關於吊裝的注意事項

請記住,與普通函式宣告不同,引用函式的變數不是懸掛的。在示例 2 中,md5Hashsha1Hash 函式在指令碼的底部定義,但可以立即在任何地方使用。無論你在何處定義函式,直譯器都會將其提升到其範圍的頂部,使其立即可用。這是變數定義的情況下,所以如下面的程式碼將打破:

var functionVariable;

hoistedFunction(); // works, because the function is "hoisted" to the top of its scope
functionVariable(); // error: undefined is not a function.

function hoistedFunction(){}
functionVariable = function(){};