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资源)
答案 0 :(得分:98)
是的,你拥有的是对的。一些说明:
bar
时都会创建foo
,但是:
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();
它会显示1
,2
,1
,2
,而非1
,2
,2
,{ {1}}。
答案 4 :(得分:0)
我创建了一个jsperf来测试嵌套与非嵌套,函数表达式与函数声明,而令我惊讶的是,嵌套测试用例的执行速度比非嵌套要快20倍。 (我预期相反或可以忽略的差异。)
https://jsperf.com/nested-functions-vs-not-nested-2/1
这是在Chrome 76,macOS上。