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

时间:2022-01-23 20:35:18
function foo(a) {
    if (/*some condition*/) {
        // perform task 1
        // perform task 3
    }
    else {
        // perform task 2
        // perform task 3
    }
}

I have a function whose structure is similar to the above. I want to abstract task 3 into a function, bar(), but I wish to limit the access of this function to only within the scope of foo(a).

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

To achieve what I want, is it right to change to the following?

为了实现我想要的,是否应该改变以下几点?

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

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

If the above is correct, does bar() get redefined every time foo(a) gets called? (worrying about waste of cpu resource here)

如果上面的内容是正确的,那么每次调用foo(a)时,bar()是否会被重新定义?(担心这里的cpu资源浪费)

4 个解决方案

#1


88  

Yes, what you have there is right. Some notes:

是的,你所拥有的是对的。一些注意事项:

  • bar is created on every call to the function foo, but:
    • On modern browsers this is a very fast process. (Some engines may well only compile the code for it once, and then reuse that code with a different context each time; Google's V8 engine [in Chrome and elsewhere] does that in most cases.)
    • 在现代浏览器中,这是一个非常快速的过程。(有些引擎可能只编译一次代码,然后每次都使用不同的上下文重用代码;谷歌的V8引擎(在Chrome和其他地方)在大多数情况下都是这样的。
    • And depending on what bar does, some engines may determine that they can "inline" it, eliminating the function call entirely. V8 does this, and I'm sure it's not the only engine that does. Naturally they can only do this if it doesn't change the behavior of the code.
    • 根据bar的功能,一些引擎可能会决定它们可以“内联”它,从而完全消除函数调用。V8这样做了,我相信它不是唯一一个这样做的引擎。当然,只有当它不改变代码的行为时,它们才能这样做。
  • 每次调用函数foo时都会创建bar,但是:在现代浏览器中,这是一个非常快速的过程。(有些引擎可能只编译一次代码,然后每次都使用不同的上下文重用代码;谷歌的V8引擎(在Chrome和其他地方)在大多数情况下都是这样的。根据bar的功能,一些引擎可能会决定它们可以“内联”它,从而完全消除函数调用。V8这样做了,我相信它不是唯一一个这样做的引擎。当然,只有当它不改变代码的行为时,它们才能这样做。
  • The performance impact, if any, of having bar created every time will vary widely between JavaScript engines. If bar is trivial, it will vary from undetectable to fairly small. If you're not calling foo thousands of times in a row (for instance, from a mousemove handler), I wouldn't worry about it. Even if you are, I'd only worry about it if I saw a problem on slower engines. Here's a test case involving DOM operations, which suggests that there is an impact, but a trivial one (probably washed out by the DOM stuff). Here's a test case doing pure computation which shows a much higher impact, but frankly even, we're talking a difference of microseconds because even a 92% increase on something that takes microseconds to happen is still very, very fast. Until/unless you saw a real-world impact, it's not something to worry about.
  • 每次创建bar对性能的影响(如果有的话)在JavaScript引擎之间会有很大的差异。如果bar是平凡的,它将从不可检测到相当小。如果您在一行中没有调用foo数千次(例如,从一个mousemove处理程序),我就不会担心它。即使你是,我也只会担心如果我发现低速引擎有问题。这里有一个涉及DOM操作的测试用例,它表明存在影响,但是影响很小(可能被DOM内容冲掉)。这是一个做纯计算的测试用例它显示了更高的影响,但坦白地说,我们说的是微秒的不同因为即使是92%的增长都是非常非常非常快的。除非你看到了现实世界的影响,否则这不是什么值得担心的事情。
  • bar will only be accessible from within the function, and it has access to all variables and arguments for that call to the function. This makes this a very handy pattern.
  • bar只能从函数内部访问,它可以访问函数调用的所有变量和参数。这使得这个模式非常方便。
  • Note that because you've used a function declaration, it doesn't matter where you put the declaration (top, bottom, or middle — as long as it's at the top level of the function, not inside a flow control statement, which is a syntax error), it gets defined before the first line of step-wise code is run.
  • 注意,因为你使用一个函数声明,没关系,你把宣言》(上、下、或中间——只要它是*的功能,不是在一个流控制语句,语法错误),它被定义在步进式的第一行代码运行。

#2


9  

This is what closures are for.

这就是闭包的用途。

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 (a closure) holds a reference to bar and only a reference to innerfoo is returned from an anonymous function which is called only once to create the closure.

Innerfoo(一个闭包)包含一个指向bar的引用,只有一个对Innerfoo的引用从一个匿名函数返回,该函数只调用一次,以创建闭包。

Bar is not accessible from the outside this way.

酒吧不能从外面通过这种方式进入。

#3


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();
        }
    };
}());

The closure keeps the scope of bar() contained, returning the new function from the self-executing anonymous function sets more visible scope to foo(). The anonymous self-executing function is run exactly once, so there is only one bar() instance, and every execution of foo() will use it.

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

#4


2  

Yes, that works fine.

是的,效果很好。

The inner function is not recreated each time you enter the outer function, but it's re-assigned.

内部函数不是在每次输入外部函数时重新创建,而是重新分配。

If you test this code:

如果您测试这个代码:

function test() {

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

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

}

test();
test();

it will show 1, 2, 1, 2, not 1, 2, 2, 2.

它会显示1 2 1 2不是1 2 2 2 2 2 2 2。

#1


88  

Yes, what you have there is right. Some notes:

是的,你所拥有的是对的。一些注意事项:

  • bar is created on every call to the function foo, but:
    • On modern browsers this is a very fast process. (Some engines may well only compile the code for it once, and then reuse that code with a different context each time; Google's V8 engine [in Chrome and elsewhere] does that in most cases.)
    • 在现代浏览器中,这是一个非常快速的过程。(有些引擎可能只编译一次代码,然后每次都使用不同的上下文重用代码;谷歌的V8引擎(在Chrome和其他地方)在大多数情况下都是这样的。
    • And depending on what bar does, some engines may determine that they can "inline" it, eliminating the function call entirely. V8 does this, and I'm sure it's not the only engine that does. Naturally they can only do this if it doesn't change the behavior of the code.
    • 根据bar的功能,一些引擎可能会决定它们可以“内联”它,从而完全消除函数调用。V8这样做了,我相信它不是唯一一个这样做的引擎。当然,只有当它不改变代码的行为时,它们才能这样做。
  • 每次调用函数foo时都会创建bar,但是:在现代浏览器中,这是一个非常快速的过程。(有些引擎可能只编译一次代码,然后每次都使用不同的上下文重用代码;谷歌的V8引擎(在Chrome和其他地方)在大多数情况下都是这样的。根据bar的功能,一些引擎可能会决定它们可以“内联”它,从而完全消除函数调用。V8这样做了,我相信它不是唯一一个这样做的引擎。当然,只有当它不改变代码的行为时,它们才能这样做。
  • The performance impact, if any, of having bar created every time will vary widely between JavaScript engines. If bar is trivial, it will vary from undetectable to fairly small. If you're not calling foo thousands of times in a row (for instance, from a mousemove handler), I wouldn't worry about it. Even if you are, I'd only worry about it if I saw a problem on slower engines. Here's a test case involving DOM operations, which suggests that there is an impact, but a trivial one (probably washed out by the DOM stuff). Here's a test case doing pure computation which shows a much higher impact, but frankly even, we're talking a difference of microseconds because even a 92% increase on something that takes microseconds to happen is still very, very fast. Until/unless you saw a real-world impact, it's not something to worry about.
  • 每次创建bar对性能的影响(如果有的话)在JavaScript引擎之间会有很大的差异。如果bar是平凡的,它将从不可检测到相当小。如果您在一行中没有调用foo数千次(例如,从一个mousemove处理程序),我就不会担心它。即使你是,我也只会担心如果我发现低速引擎有问题。这里有一个涉及DOM操作的测试用例,它表明存在影响,但是影响很小(可能被DOM内容冲掉)。这是一个做纯计算的测试用例它显示了更高的影响,但坦白地说,我们说的是微秒的不同因为即使是92%的增长都是非常非常非常快的。除非你看到了现实世界的影响,否则这不是什么值得担心的事情。
  • bar will only be accessible from within the function, and it has access to all variables and arguments for that call to the function. This makes this a very handy pattern.
  • bar只能从函数内部访问,它可以访问函数调用的所有变量和参数。这使得这个模式非常方便。
  • Note that because you've used a function declaration, it doesn't matter where you put the declaration (top, bottom, or middle — as long as it's at the top level of the function, not inside a flow control statement, which is a syntax error), it gets defined before the first line of step-wise code is run.
  • 注意,因为你使用一个函数声明,没关系,你把宣言》(上、下、或中间——只要它是*的功能,不是在一个流控制语句,语法错误),它被定义在步进式的第一行代码运行。

#2


9  

This is what closures are for.

这就是闭包的用途。

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 (a closure) holds a reference to bar and only a reference to innerfoo is returned from an anonymous function which is called only once to create the closure.

Innerfoo(一个闭包)包含一个指向bar的引用,只有一个对Innerfoo的引用从一个匿名函数返回,该函数只调用一次,以创建闭包。

Bar is not accessible from the outside this way.

酒吧不能从外面通过这种方式进入。

#3


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();
        }
    };
}());

The closure keeps the scope of bar() contained, returning the new function from the self-executing anonymous function sets more visible scope to foo(). The anonymous self-executing function is run exactly once, so there is only one bar() instance, and every execution of foo() will use it.

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

#4


2  

Yes, that works fine.

是的,效果很好。

The inner function is not recreated each time you enter the outer function, but it's re-assigned.

内部函数不是在每次输入外部函数时重新创建,而是重新分配。

If you test this code:

如果您测试这个代码:

function test() {

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

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

}

test();
test();

it will show 1, 2, 1, 2, not 1, 2, 2, 2.

它会显示1 2 1 2不是1 2 2 2 2 2 2 2。