admin管理员组文章数量:1389978
I am learning JavaScript through this website. The link is to the specific chapter that I'm reading right now.
In the book, the author talks about keeping the implementation details of a module on a local scope. He achieves it by doing:
var dayName = function() {
var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
return function(number) {
return names[number];
};
}();
I understand how this works, but I do not understand why he is doing it this way. Why wouldn't he just do...
function dayName(number) {
var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
return names[number];
}
...which to me looks like a much cleaner and readable code? Given his goal of keeping names
within local scope, creating a nested lambda seems redundant.
Is there any real advantage to using the nested function in this case? Or is he using it just for educational purposes?
Thanks!
I am learning JavaScript through this website. The link is to the specific chapter that I'm reading right now.
In the book, the author talks about keeping the implementation details of a module on a local scope. He achieves it by doing:
var dayName = function() {
var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
return function(number) {
return names[number];
};
}();
I understand how this works, but I do not understand why he is doing it this way. Why wouldn't he just do...
function dayName(number) {
var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
return names[number];
}
...which to me looks like a much cleaner and readable code? Given his goal of keeping names
within local scope, creating a nested lambda seems redundant.
Is there any real advantage to using the nested function in this case? Or is he using it just for educational purposes?
Thanks!
Share Improve this question asked Mar 31, 2017 at 2:51 spicypumpkinspicypumpkin 1,2192 gold badges12 silver badges21 bronze badges 5- 3 One may say that it would reduce the garbage collector pressure by not re-allocating the same array multiple times. (but surely it's negligible, unless you invoke this function million times a second) – zerkms Commented Mar 31, 2017 at 2:54
- Possible duplicate of JavaScript Why return function in a function? – Matt Commented Mar 31, 2017 at 2:54
- 1 @mkaatman The post is asking about how closures work, and I understand it (or at least I think I do). I'm wondering why the author is approaching the problem this way, not the alternative (my example). – spicypumpkin Commented Mar 31, 2017 at 3:00
- Read through some of the ments on the duplicate and check out this article specifically: davidwalsh.name/javascript-functions – Matt Commented Mar 31, 2017 at 3:02
- 1 @mkaatman the "duplicate" is about something else. – zerkms Commented Mar 31, 2017 at 3:02
5 Answers
Reset to default 2The toy example you show is not very pelling. The main advantage of writing it that way is that the array is only created once, rather than every time you call the function. This makes it a little faster, at the expense of keeping the array allocated for the entire session (a mon time-space tradeoff). In practice, few people program this way.
The technique bees more useful when you have multiple functions and they operate on shared data. If one of the functions modifies the variable, this is remembered in the closure, and visible to other functions when they're called later.
var dayName = function() {
var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
return {
getDay: function(number) {
return names[number];
},
setDay: function(number, newName) {
names[number] = newName;
}
};
}();
Now you can write:
console.log(dayName.getDay(3)); // prints "Wednesday"
dayObj.setDay(3, "Mercredi");
console.log(dayName.getDay(3)); // prints "Mercredi"
You can't do this with your second form of the function, because it has no memory from one call to the next.
One case when you might return a function like that is when creating multiple similar event listeners. For example, suppose you have buttons named button1
, button2
, and button3
. You can add click listeners like this (using JQuery for brevity):
button1.click(() => console.log(1));
button2.click(() => console.log(5));
button1.click(() => console.log(42));
This can be written instead as:
function makeLogger(x) {
return () => console.log(x);
}
button1.click(makeLogger(1));
button2.click(makeLogger(5));
button1.click(makeLogger(42));
This makes an even bigger difference if you can't use the arrow function for patibility reasons (not using Babel).
In modern JavaScript you'd put code like that in a module (CommonJS, AMD or ES6). In which case something this would be fine
const names = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
function dayName(number) {
return names[number];
}
module.exports = {
dayName: dayName,
};
Otherwise yes, it does make some sense to do it his way. Your way you're recreating the names array every time you execute the function. His way it's only created once and it doesn't pollute the namespace (no one else except dayName
can see the names
array.
You should really look into using modules of one type or another though.
In answer to the question When are nested functions generally appropriate in JavaScript? the general answer is, when you want a closure.
In the case you posted the inner function is a closure. It closes over the names
variable.
Closures are a pretty basic and mon feature of JavaScript. They are especially useful with callbacks.
One possible advantage of this code is caching the result of a highly putational code which has to be done only once (although this is rare) and then using that result for other purposes. Browser related variables are generally cached using this strategy.
You said:
I understand how this works, but I do not understand why he is doing it this way
If you do not understand why he is doing it this way then you don't really understand how it really works.
What you see in that example is a closure. And in my opinion this is a better introduction to closures than a lot of the introductory examples out there.
A closure is a bit like a global variable. When using a global variable a function access data outside its own scope. For example:
var x = 2;
function amplify (n) {
return n * x; // here a function is using x which does not exist
// in the function's own scope
}
Closures are similar, except that they are hidden in global scope. Every time an inner function access a variable form an outer function it does so using the same mechanism as how global variables work except that that variable is not visible form global scope. Let's now see a simple example similar to the one in your post:
var amplify;
function init () {
var x = 2;
amplify = function (n) { return n * x };
};
init();
console.log(amplify(5)); // prints 10
console.log(x); // syntax error
So in this case, as in the code you posted, the variable x
behaves like a global variable but is invisible in global scope. Just like global variables it is visible to all functions declared in the scope it's in. And because x
is used by the amplify()
function it is not freed or garbage collected when the init()
function returns. And that is all what closures are about - this weird contradictory concept of private globals. Nothing more.
In this specific use-case the advantages are minimal. You save memory by not allocating the array each time you call the function but that's about it. But closures are much more powerful than that. You can for example share the same variables with multiple functions yet still hide it from global scope. For example:
var amplify;
var setFactor;
var getFactor;
function init () {
var x = 2;
amplify = function (n) { return n * x };
setFactor = function (n) { x = n };
getFactor = function () { return x };
};
init();
amplify(5); // returns 10
getFactor(); // returns 2
setFactor(4);
amplify(5); // returns 20
console.log(x); // still a syntax error
As you can see. Closures allow you to capture and share data amongst related functions yet hide that data from all other functions. In a way, closures are almost functional equivalents to objects. So my guide of when to use closures is when you need modularisation but objects are overkill. The most mon use-case for this is capturing state for callbacks. But caching (memoization), as shown by the example code you posted, is a good use-case as well.
本文标签: When are nested functions generally appropriate in JavaScriptStack Overflow
版权声明:本文标题:When are nested functions generally appropriate in JavaScript? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744670185a2618776.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论