在javascript中定义另一个函数内的函数

时间:2012-04-18 06:58:24

标签: javascript

function foo(a) {
    if (/*some condition*/) {
        // perform task 1
        // perform task 3
    }
    else {
        // perform task 2
        // perform task 3
    }
}

我有一个结构类似于上面的函数。我想将任务3 抽象为函数bar(),但我希望将此函数的访问权限限制在foo(a)的范围内。

要实现我想要的目标,改为以下是否正确?

function foo(a) {
    function bar() {
        // perform task 3
    }

    if (/*some condition*/) {
        // perform task 1
        bar();
    }
    else {
        // perform task 2
        bar();
    }
}

如果上述情况正确,每次调用bar()foo(a)都会重新定义吗? (担心这里浪费cpu资源)

5 个答案:

答案 0 :(得分:98)

是的,你拥有的是对的。一些说明:

    每次调用函数bar时都会创建
  • foo,但是:
    • 在现代浏览器上,这是一个非常快速的过程。 (有些引擎可能只编译代码一次,然后每次使用不同的上下文重用该代码; Google的V8引擎[在Chrome和其他地方]在大多数情况下都会这样做。)
    • 根据bar的作用,某些引擎可能会确定它们可以“内联”它,完全取消函数调用。 V8这样做,我确信它不是唯一的引擎。当然,只有在不改变代码行为的情况下,他们才能这样做。
  • 每次创建bar的性能影响(如果有)在JavaScript引擎之间会有很大差异。如果bar是微不足道的,那么它将从不可检测到相当小的变化。如果你没有连续几次调用foo(例如,来自mousemove处理程序),我不会担心它。即使你是,如果我在较慢的发动机上看到问题,我只会担心它。 Here's a test case involving DOM operations,这表明存在影响,但是一个微不足道的影响(可能被DOM的东西淘汰)。 Here's a test case doing pure computation显示出更高的影响,但坦率地说,我们正在谈论 micro 秒的差异,因为即使在 micro 的某些事情上增加了92%发生的秒数仍然非常非常快。除非你看到现实世界的影响,否则不必担心。
  • bar只能从函数中访问,并且可以访问该函数调用的所有变量和参数。这使得它成为一种非常方便的模式。
  • 请注意,因为您使用了函数声明,所以在声明的位置(顶部,底部或中间)无关紧要 - 只要它位于函数的顶层,不是在流控制语句中,这是一个语法错误),它在第一行逐步代码运行之前定义。

答案 1 :(得分:14)

这就是闭包的目的。

var foo = (function () {
  function bar() {
    // perform task 3
  };

  function innerfoo (a) { 
    if (/* some cond */ ) {
      // perform task 1
      bar();
    }
    else {
      // perform task 2
      bar();
    }
  }
  return innerfoo;
})();

Innerfoo(一个闭包)保存对bar的引用,并且只从匿名函数返回对innerfoo的引用,该函数只调用一次以创建闭包。

这种方式无法从外面访问酒吧。

答案 2 :(得分:8)

var foo = (function () {
    var bar = function () {
        // perform task 3
    }
    return function (a) {

        if (/*some condition*/) {
            // perform task 1
            bar();
        }
        else {
            // perform task 2
            bar();
        }
    };
}());

闭包保持bar()的范围,从自执行匿名函数返回新函数将更明显的范围设置为foo()。匿名自执行函数只运行一次,因此只有一个bar()实例,foo()的每次执行都会使用它。

答案 3 :(得分:2)

是的,这很好。

每次输入外部函数时都不会重新创建内部函数,但会重新赋值。

如果您测试此代码:

function test() {

    function demo() { alert('1'); }

    demo();
    demo = function() { alert('2'); };
    demo();

}

test();
test();

它会显示1212,而非122,{ {1}}。

答案 4 :(得分:0)

我创建了一个jsperf来测试嵌套与非嵌套,函数表达式与函数声明,而令我惊讶的是,嵌套测试用例的执行速度比非嵌套要快20倍。 (我预期相反或可以忽略的差异。)

https://jsperf.com/nested-functions-vs-not-nested-2/1

这是在Chrome 76,macOS上。