匿名函数
定义匿名函数
定义函数时,通常会给它命名,然后使用该名称调用它,如下所示:
foo();
function foo(){
// ...
}
当你以这种方式定义函数时,Javascript 运行时将你的函数存储在内存中,然后使用你为其指定的名称创建对该函数的引用。然后可以在当前范围内访问该名称。这可以是创建函数的一种非常方便的方法,但 Javascript 不要求你为函数指定名称。以下也是完全合法的:
function() {
// ...
}
如果定义的函数没有名称,则称为匿名函数。该函数存储在内存中,但运行时不会自动为你创建对它的引用。乍一看,似乎这样的东西似乎毫无用处,但有几种情况下匿名函数非常方便。
为变量分配匿名函数
匿名函数的一个非常常见的用途是将它们分配给变量:
var foo = function(){ /*...*/ };
foo();
函数作为变量更详细地介绍了匿名函数的使用
将匿名函数作为参数提供给另一个函数
某些函数可以接受对函数的引用作为参数。这些有时被称为依赖注入或回调,因为它允许你的调用函数回调你的代码,让你有机会改变被调用函数的行为方式。例如,Array 对象的 map 函数允许你遍历数组的每个元素,然后通过将变换函数应用于每个元素来构建新数组。
var nums = [0,1,2];
var doubledNums = nums.map( function(element){ return element * 2; } ); // [0,2,4]
创建一个命名函数将是繁琐,草率和不必要的,这将使你的范围变得杂乱,只需要在这一个地方需要的功能,并打破代码的自然流程和读取(同事必须留下此代码才能找到你的代码)功能,以了解正在发生的事情)。
从另一个函数返回匿名函数
有时将函数作为另一个函数的结果返回是有用的。例如:
var hash = getHashFunction( 'sha1' );
var hashValue = hash( 'Secret Value' );
function getHashFunction( algorithm ){
if ( algorithm === 'sha1' ) return function( value ){ /*...*/ };
else if ( algorithm === 'md5' ) return function( value ){ /*...*/ };
}
立即调用匿名函数
与许多其他语言不同,Javascript 中的作用域是功能级别,而不是块级别。 (参见函数范围 )。但是,在某些情况下,有必要创建一个新范围。例如,在通过 <script>
标记添加代码时创建新范围很常见,而不是允许在全局范围内定义变量名(这会冒其他脚本与变量名冲突的风险)。处理这种情况的常用方法是定义一个新的匿名函数,然后立即调用它,安全地将变量隐藏在匿名函数的范围内,而不会通过泄漏的函数名使第三方访问你的代码。例如:
<!-- My Script -->
<script>
function initialize(){
// foo is safely hidden within initialize, but...
var foo = '';
}
// ...my initialize function is now accessible from global scope.
// There's a risk someone could call it again, probably by accident.
initialize();
</script>
<script>
// Using an anonymous function, and then immediately
// invoking it, hides my foo variable and guarantees
// no one else can call it a second time.
(function(){
var foo = '';
}()) // <--- the parentheses invokes the function immediately
</script>
自引用匿名函数
有时,匿名函数能够引用自身是有用的。例如,函数可能需要递归调用自身或向自身添加属性。但是,如果该函数是匿名的,则这可能非常困难,因为它需要知道已分配函数的变量。这是不太理想的解决方案:
var foo = function(callAgain){
console.log( 'Whassup?' );
// Less then ideal... we're dependent on a variable reference...
if (callAgain === true) foo(false);
};
foo(true);
// Console Output:
// Whassup?
// Whassup?
// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
console.log('Bad.')
};
bar(true);
// Console Output:
// Whassup?
// Bad.
这里的意图是匿名函数以递归方式调用自身,但是当 foo 的值发生变化时,最终会出现一个可能难以追踪的错误。
相反,我们可以通过给它一个私有名称给匿名函数一个自己的引用,如下所示:
var foo = function myself(callAgain){
console.log( 'Whassup?' );
// Less then ideal... we're dependent on a variable reference...
if (callAgain === true) myself(false);
};
foo(true);
// Console Output:
// Whassup?
// Whassup?
// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
console.log('Bad.')
};
bar(true);
// Console Output:
// Whassup?
// Whassup?
请注意,函数名称的范围是自身。该名称尚未泄露到外部范围:
myself(false); // ReferenceError: myself is not defined
在将递归匿名函数作为回调参数处理时,此技术特别有用:
Version => 五
// Calculate the fibonacci value for each number in an array:
var fib = false,
result = [1,2,3,4,5,6,7,8].map(
function fib(n){
return ( n <= 2 ) ? 1 : fib( n - 1 ) + fib( n - 2 );
});
// result = [1, 1, 2, 3, 5, 8, 13, 21]
// fib = false (the anonymous function name did not overwrite our fib variable)