正常的函数声明如下所示:
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中,您可以对函数执行相同的操作:
// 例子1 var hashAlgorithm = 'sha1'; var hash; if ( hashAlgorithm === 'sha1' ) hash = function(value){ /*...*/ }; else if ( hashAlgorithm === 'md5' ) hash = function(value){ /*...*/ }; hash('Fred');
在上面的示例中,hash是一个普通变量。为其分配了对函数的引用,此后可以像常规的函数声明一样,使用括号将其引用的函数调用。
上面的示例引用了匿名函数...这些函数没有自己的名称。您还可以使用变量来引用命名函数。上面的示例可以这样重写:
// 例子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){ // ... }
或者,您可以从对象属性分配函数引用:
// 例子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');
您可以通过省略括号来将对一个变量所拥有的功能的引用分配给另一个变量。这可能导致容易犯的错误:尝试将一个函数的返回值分配给另一个变量,但是不小心将引用分配给了该函数。
// 例子4 var a = getValue; var b = a; // b现在是对getValue的引用。 var c = b(); // b被调用,因此c现在保存getValue返回的值(41) function getValue(){ return 41; }
对函数的引用与其他任何值一样。如您所见,可以将引用分配给变量,然后将该变量的引用值分配给其他变量。您可以像其他任何值一样传递对函数的引用,包括传递对函数的引用作为另一个函数的返回值。例如:
// 例子5 // getHashingFunction返回一个函数,该函数已分配 // 哈希供以后使用: var hash = getHashingFunction( 'sha1' ); // ... hash('Fred'); // 返回与给定algorithmName对应的函数 function getHashingFunction( algorithmName ){ // 返回对匿名函数的引用 if (algorithmName === 'sha1') return function(value){ /**/ }; // 返回对已声明函数的引用 else if (algorithmName === 'md5') return md5; } function md5Hash(value){ // ... }
您无需为变量分配函数引用即可调用它。本示例以示例5为基础,将调用getHashingFunction,然后立即调用返回的函数并将其返回值传递给hashedValue。
// 例子6 var hashedValue = getHashingFunction( 'sha1' )( 'Fred' );
请记住,与普通函数声明不同,引用函数的变量不会“提升”。在示例2中,md5Hashandsha1Hash函数在脚本的底部定义,但立即可在任何地方使用。无论在何处定义函数,解释器都会将其“提升”到其作用域的顶部,使其立即可用。这是不变量定义的情况下,所以如下面的代码将打破:
var functionVariable; hoistedFunction(); // works, because the function is "hoisted" to the top of its scope functionVariable(); // 错误:未定义不是函数。 function hoistedFunction(){} functionVariable = function(){};