Lately, I have been seeing in my companies production code return with closure functions. Such as return (function() {...}()); And I do not like to see this, but I am not an authoritative source. I thought I would ask StackOverflow why and when this good/bad to use.
* NOTE *
Say your not concerned about namespace pollution because all of these functions are already in their on closure.
Example1a:
function foo(bar) {
return {
x: 1 + bar,
y: 1 - bar,
duration: (function() {
var i = 0,
len = 5;
var results = 0;
for (; i < bar; i++) {
results += 1 + (results * bar);
}
return results;
}())
};
}
Example1b:
function barProcess(bar) {
var i = 0;
var len = 5;
var results = 0;
for (; i < bar; i++) {
results += 1 + (results * bar);
}
return results;
}
function foo(bar) {
return {
x: 1 + bar,
y: 1 - bar,
duration: barProcess(bar)
};
}
Example1c:
function foo(bar) {
var i = 0;
var len = 5;
var results = 0;
for (; i < bar; i++) {
results += 1 + (results * bar);
}
return {
x: 1 + bar,
y: 1 - bar,
duration: results
};
}
Observation:
Example1a:
The inner function takes advantage of closure if there is a need.
Example1b:
In case barProcess could require some closure which could make the argument list long and problematic to maintain.
Example1c:
There is no extra function creation per invocation.
It is easiest to debug (in my opinion).
Please if someone can give me some technical reasons for why Example a, b, or c should be used that would be fantastic.
So, my lame answer did not satisfy me, so I tried this. JS Perf Tests. Which I think to make my observations not too far off.
I don't think its possible to choose a clear winner between examples a,b anc c for every simple case.
In the example you give, version (c) is good enough so I would go with it. That said, version (a) keeps the i, len and results veriables in an even tighter scope so it definitely could be a good way to go if you want to keep "x" and "y" more separate from duration "b".
I'm not a fan of splitting things into separate named functions just for organizational or scoping reasons, like you did on example (b), because it tends to make the code more complicated and harder to follow. However, if the barProccess is an actual reuseable abstraction that you can give a clear name for then keeping it separate might be a good idea.
Say your not concerned about namespace pollution because all of these functions are already in their on closure.
I think you are exagerating a bit here. The inner IFFE is not 100% recommended like the outer IFFE is but restricting scope even more is still perfectly OK and I don't think its worth fighting against your coleagues over it.
1a: No closure is formed as the outer function, foo(), has not returned when the inner function executes. The inner function is an anonymous "self-executing" subroutine. Whereas a self-executing function can form a closure, this one neither does nor needs to. This is a slightly "showy" way to structure the code.
1b: No closure is formed as the outer function, foo(), straightforwardly calls the named function barProcess(), which returns a numeric value, not a function. This approach would be useful if barProcess() is also to be called from elsewhere in the code.
1c: No closure is formed. foo() comprises a straightforward block of code, which is simple to understand and will certaily do the job. As javascript for loops don't have their own scope, foo() will simplify to :
function foo(bar) {
for(var i=0, results=0; i<bar; i++) {
results += 1 + (results * bar);
}
return {
x: 1 + bar,
y: 1 - bar,
duration: results
};
}
Related
I'm studying JavaScript from the book JavaScript: The Good Parts, in the memoization section there is an example about using memoize technique to do Fibonacci problem
We create a general function call memoizer, it takes an memo array and the fundamental function, returns a shell function that manages the memo and calls fundamental function
var memoizer = function(memo, fundamental) {
var shell = function(n) {
var result = memo[n];
if (typeof result !== 'number') {
result = fundamental(shell, n);
memo[n] = result;
}
return result;
};
return shell;
};
And then create fibonacci like this:
var fibonacci = memoizer([0, 1], function(shell, n) {
return shell(n-1) + shell(n-2);
});
If I run fibonacci(10), the result will be displayed exactly.
But the thing that makes me confused is the n parameter shell function in memoizer function. I know that it is the value that we want to compute. But where is it come from? How can I call fibonacci(10), for example, can pass the value 10 to n? And what is exactly the var fibonacci? Is it a function or points to a function object as memoizer?
Thanks for any help!
So, to understand this fully, you need to understand things below as fundamental pieces.
Closure How do JavaScript closures work?
Scope What is the scope of variables in JavaScript?
First class object What is meant by 'first class object'?
So, now look at the code.
var memoizer is assigned as a function that returns an another function inside.
var memoizer = function(memo, fundamental) {
var shell = function(n) {
... do some works ...
};
return shell;
};
Can you see it? var shell is returned at the end of the line in memoizer
And whatever the inner logic is in memoizer, the result of it is assigned to var fibonacci
var fibonacci = memoizer([0, 1], function(shell, n) {
return shell(n-1) + shell(n-2);
});
So, it means fibonacci equals the result of memoizer (Since we excuted it), and the result of memoizer equals shell function. If you read those links given to you by me well, you can understand what is going on behind the scenes.
By the way, the code you've given isn't the best way. Because anyway closure makes an activated object alive that isn't necessary.
This code below is an another way of making fibonacci, this isn't the absolute best way, however, I recommend you to compare this code with your code, and figure the differences out.
var result = [];
result[0] = 1;
result[1] = 1;
function fibonacci(n){
var i;
for(i = 2; i < n; i++){
if(!result[i]){
result[i] = result[i-1] + result[i-2];
}
}
return result[i-1];
}
console.log(fibonacci(10));
I have a dice-rolling bot that spits out results via var roll = new Roll('4#2d20+3'). That constructor makes objects with properties parsed out of the string argument, which resembles this:
aRoll = {
text: '4#2d20+3',
times: 4,
dice: 2,
sides: 20,
modifier: 3,
roll: function() {...}
}
The roll() method should use the object's properties to generate an array of results. This is an exercise to learn what's new in JavaScript, so I'm curious how best to accomplish this.
Old, procedural way:
this.roll = function() {
var total = 0;
for (var i=0; i < this.dice; i++) {
total += Math.floor(Math.random() * this.sides) + 1;
}
return total;
}
My attempt at new Array functional iteration:
this.roll = () => Array(this.dice).fill(0).reduce(state => {
result + Math.floor(Math.random() * state.sides) + 1;
}, this);
This sorta works, but Array(x).fill(0).reduce(... is an ugly hack, and passing this in as state seems like a sign I'm doing the wrong thing.
Is there an Array method I should use instead? Or is the for loop still the cleanest way to accomplish this?
One way to repeat a function n times is
Array.from(Array(n), fn)
To make all of this more readable, you could define, for example
let times = (n, fn) => Array.from(Array(n), fn);
let rand = n => Math.floor(Math.random() * n) + 1;
let sum = a => a.reduce((x, y) => x + y);
and then
roll = function() {
return sum(
times(this.dice,
rand.bind(0, this.sides)));
}
I think I figured out how this “should” be done.
The first issue is straightforward: do not use arrow functions as methods:
An arrow function does not create its own this context, so this has its original meaning from the enclosing context.
this is the whole point of object-orientation, so breaking it is a bad idea. Passing this as map()’s second argument was indeed a code smell.
The second issue: instead of abusing reduce()’s initial value parameter with this to fake a context object, use a closure:
function roll(sides) {
return (total) => {
total + Math.floor(Math.random() * sides) + 1;
};
}
someArray.map(roll(this.sides));
When you pass callbacks as arguments, but need to dynamically give them data that callers don’t provide, closures are the classic solution.
As for the third issue, populating an array the size of an object property, in order to call a function that many times…
There is no built-in boilerplate way. :•) #georg kindly provided a clean implementation of a times() function that reminds me of Ruby’s Number.times(), if you’re interested.
The W3Schools example for a JS for-each loop (http://www.w3schools.com/js/js_loop_for.asp) is
var person = {fname:"John", lname:"Doe", age:25};
var text = "";
var x;
for (x in person) {
text += person[x];
}
and I'm wondering if there's any particular reason why x is defined outside of the loop if it's only used inside the loop in that particular example, or if that's necessary condition for defining a for-each loop, and if so, why?
This is(/was) an old convention, meant largely to indicate that x does not exist only inside the loop.
Declaring variables at the top of a function is not necessary and is variously encouraged/discouraged by different style tools. It can be convenient to group variable declarations in one place, but may increase the distance between declaration and use (generally considered a bad thing).
In JS, the var declaration works at function-scope, so variables are hoisted to the top of the nearest function and live for the duration of the function. See:
function foo() {
for (var i = 19; i > 0; --i) {
console.log(typeof i); // number
}
console.log(typeof i); // number
}
foo();
Because the variable is accessible throughout the function, it is declared at the start of the function (C used to require this).
ES6 has changed this with the let statement, which introduces the more common block-level scoping. With let, the variable is only available inside of the loop:
function foo() {
for (let i = 19; i > 0; --i) {
console.log(typeof i); // number
}
console.log(typeof i); // undefined
}
I am still fighting my battle against my low IQ :D
This is the usual infamous cycle with closures:
function r(){
var a = [];
var i;
for(i=0;i<10;i++){
a[i]=(function(x){
return function(){return x;}
})(i);
return a;
}
This is quite clear to me now.
In order to understand closures better, I played with the code and came up with:
function r(){
var a = [];
var i;
for(i=0;i<10;i++){
a[i] = (function(){
var x=i;
return function(){return x;}
})();
}
return a;
}
Is my code fully equivalent?
Merc.
Is my code fully equivalent?
Yes.
I find it slightly easier to read the second way, because it saves having to look to the end of the immediately-executed function to find out what's passed in as a parameter (not that that's a big problem with short functions like this), but the first way is more compact and probably more common so...
I guess you didn't try them, the first one doesn't even work! Use firebug to test your code. Here is a version of the first example which actually doesn't give errors:
function r() {
var a = [];
var i;
for (i=0; i<10; i++) {
a[i] = (function (x) {
return function () {
return x;
}
})(i);
}
return a;
}
So, after adding the missing closing brace, they are equivalent, they build an array of functions that return the numbers from 0 to 9, they don't build an array of numbers from 0 to 9. So for example, calling r()[5](); returns 5 (is the sixth element of the array).
I was reviewing some today, when I encountered the following convention :
TestParam(1);
function TestParam(p){
var p = p + 1;
alert(p); // alerts '2'
}
Now, obviously, the developer didn't mean to delcare 'p' within the function, instead maybe meaning:
p = p + 1;
But the code still worked, i.e. the value alerted was "2". So it got me to thinking. What would happen in the following scenario:
var a = 1;
TestParam(a);
alert(a); // alerts "1"
function TestParam(p){
var p = p + 1;
alert(p); // alerts '2'
}
Again the alerts were as I suspected (as intimated in the comments above). So then I was curious as to what would happen if I used an object:
var a = { b: 1 };
TestParam(a);
alert(a.b); //alerts 1
function TestParam(p) {
var p = {b:p.b + 1};
alert(p.b); //alerts 2
}
So, in this instance, JavaScript has 'remembered' the variable a, even though when it is passed to TestParam as p, p is redeclared.
Now if I were to have done the following within the function, then both alerts would have been "2"
p.b++;
//var p = {b:p.b + 1};
I.e. it would have modified the member b of the original object. I get this. Its the previous scenario that baffles me!
I realise this is quite a hypothetical question that is unlikely to carry much real-world usefulness, but it still made me quite curious, as to what is going on in the background, and how exactly JavaScript is scoping and referencing these variables.
Any thoughts?
Variables are scoped to the enclosing function in JavaScript. And you can declare them as many times as you like.
Objects are not tied to variables; many variables can refer to the same object. (This is sometimes called aliasing.) This is what's happening in your last example. JavaScript has not "remembered" the variable a at all; rather, p and a refer to the same object, so when it is changed via p, you can see those changes via a.
Here's an example that might make more sense to you. Sometimes a person has more than one identity.
var Clark = new Person;
var Superman = Clark; // Maybe not everybody needs to know these two are
// the same person, but they are.
Clark.eyes = "brown";
alert(Superman.eyes); // should be brown, right?
Knowing the rules of the language you're using has tremendous "real-world usefulness". Not understanding these two rules is the source of a lot of confusion and bugs.
Javascript generally passes all arguments to functions by reference except when the argument is a number or a string. Javascript passes numbers and strings by value which is why your first example works the way it does.
I believe there's a typo in your code. I think you mean:
function TestParam(p) {
var p = {b:p.b + 1}; // p.b, not p.a (p.a == undefined)
alert(p.b);
}
In your example:
var a = { b: 1 }; // "a" is defined in the global scope
TestParam(a);
alert(a.b); // alerts 1
function TestParam(p) {
var p = {b:p.a + 1}; // "p" is defined in TestParam()'s scope
/* But not until after the expression on the right side of the assignment
has completed--that's why you can use p.a
alert(p.a); //alerts 2
}
At first, "p" is passed as a reference to the global variable "a", but then you redefine it in the first line. So, for example:
var a = { b: 1 };
alert(a.b); // Alerts 1
TestParam(a);
alert(a.b); // Alerts 2
TestParam(a);
alert(a.b); // Alerts 3
function TestParam(p) {
p.b++;
}