匿名函数

定义匿名函数

定义函数时,通常会给它命名,然后使用该名称调用它,如下所示:

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)