可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Nested helper functions can be useful for making your code more understandable. Google even recommends using nested functions in their style guide. I'm wondering about the instantiation of these nested functions and performance. For example,
work(1);
work(2);
function work(a) {
// do some stuff
log();
// do some more stuff
function log() {
console.log(a);
}
}
work
is instantiated once, but is log
instantiated twice?
If log
is instantiated every time work
is executed, would it generally be recommended not to nest functions? Instead, write code like the following
work(1);
work(2);
function work(a) {
// do some stuff
log(a);
// do some more stuff
}
function log(a) {
console.log(a);
}
These examples are overly trivial and the question is more about the general case.
回答1:
work is instantiated once, but is log instantiated twice?
Yes, on each call to work.
would it generally be recommended not to nest functions?
Why not? I presume you're hinting at performance issues.
Whether a practice is good or bad depends on your reasons for using it. In the case of simple helpers, it's good to keep them local because it means you can make them suitable just for your special case and not worry about the extra cruft of a general function. E.g. to pad a number with a leading zero:
function pad(n) {
return (n<10? '0' : '') + n;
}
works very well as a helper where n is expected to always be in the range 0 to 99, but as a general function is missing a lot of features (dealing with non–number n, -ve numbers, etc.).
If you are concerned about performance, you can always use a closure so the helper is only instantiated once:
var work = (function() {
function log() {
console.log(a);
}
return function (a) {
// do some stuff
log();
// do some more stuff
};
}());
Which can also make sense where log is used by more than one function within the closure.
Note that for a single case, this is very much a micro optimisation and not likely to deliver any noticeable difference in performance.
回答2:
Nested function-objects are instantiated and added to the LexicalEnvironment
created when an enclosing function is run. Each of these nested functions will also have a [[Scope]]
property created on them. In addition when a nested function is run, a new LexicalEnvironment
object will be created and the [[Scope]]
copied to its outer
property.
When the enclosing function completes, then the nested function-object and its associated memory will be eligible for garbage collection.
This process will repeat for every call to the outer function.
Contrast this with your second implementation, where the function-object need only be created once; likewise its garbage collection.
If this is a "hot" function (i.e. called many times) then the second implementation is infinitely preferable.
回答3:
RobG is right. Performance us affected by instantiating functions for each work thread. Whether it is a noticeable problem or not really comes down to how many simultaneous active working threads you have, as this affects memory consumption as well as execution speed.
If performance is a big issue on your application (e.g. a complex, heavy function) and you only want to use the function in one place, closures are the way to go.
If the function you're calling from "work" is to be used from several parts of your code, it's better to keep them separate instead of nesting them. This makes to keep the code updated simpler (as you only update it in one place).
Most JS engines parse code only once (even for nested functions) so the work involved in instantiating functions is not a big issue.
Memory usage, on the other side, can be an issue if you have many nesting levels as well as several simultaneous threads or event listeners, so nesting should be managed carefully in these cases (on large-scale applications).
回答4:
Yes. Instantiation occurs each time you invoke the nested functions. Instantiating functions does use CPU time but it's not as important as parsing.
So, for the general case (not the case now that you mention that your functions will be invoked many times per second), parsing time is more relevant than instantiation.
In this case, nesting functions will use a lot of memory and CPU time,CSO it's best to use RobG's solution (closures), where functions are instantiated once and they are simply called, causing less memory usage.
If you want more optimized code in this critical piece of code, you should try to use as few functions as possible as this will work faster, albeit at the expense of losing code readability and maintainability.