How does the Javascript closure with function works? - javascript

Hi i have been exploring closures and javascript core concepts i couldn't understand why does the console.log(factory[i]) outputs undefined i have pushed my function inside there right? And if i call temp outside the loop it says undefined whereas if i call inside the loop it returns am bit confused can anyone explain me?Here is my code
var fruits=["apple","orange"];
var factory=[];
for(var i=0;i<fruits.length;i++)
{
var temp=function()
{
console.log(fruits[i]);
}
factory.push(temp());
}
temp();
console.log(factory);
for(var i=0;i<factory.length;i++)
{
temp(i);
console.log(factory[i]);
}
https://jsfiddle.net/kh3okLca/

You are not passing function but the result of the executed function temp() as it don't return anything its undefined. change factory.push(temp()); to factory.push(temp);
The temp() outside return undefined because by that time loop has executed and the value of i is 2 check this following piece of code which logs value of i.
var fruits=["apple","orange"];
var factory=[];
for(var i=0;i<fruits.length;i++)
{
var temp=function()
{
console.log(fruits[i],"console",i);
}
factory.push(temp);
}
temp();
console.log(factory,"factory");
for(var i=0;i<factory.length;i++)
{
temp(i); //i resets to 0 here in same scope
console.log(factory[i](i),"factoryi"); //this doesnt return anything so its undefined but statements are executed
}

Here is the output you have.
//next two executed due to factory.push(temp()) in first if loop
& there is a console.log there inside the function
apple
orange
//here i++ in first loop will be 3, but array have only two element, so it is undefined
undefined
// due to console.log(factory)
// temp function is actually returning undefined,
[undefined, undefined]
// due to temp(i) in second if block
apple
// but factory array is stil empty so factory[i] will be undefined
undefined
from temp orange
undefined

Closure are nothing but function with preserve data. Till now a function is treated as peace of code which takes input and produces some output ,for every function call this code remain same, but closure gives you opportunity to save some data with the function which can be changed so that for each function call it will react differently, keep that in mind everything will be easy .
Suppose you have a function that finds rate of interest , but this functions is used by three teams whose interest rates are different, So in general what we do we pass the team name with the principle amount , each and everytime we have to pass the team name , So by using closure we can three instance of a function for each team (team name as a preserve data ) and now only send the principle amount and get the interest calculated according to the team, I a moment i will add example also,

Related

Where does the parameter of a returned function get its value?

I don't know if I chose the right title for this question, and maybe this is why I cannot also find an answer to this question.
While reading a javascript book, I found this example while talking about closures.
function multiplier(factor){
console.log('factor:'+factor);
return function(number){
console.log('number:'+number)
return number * factor;
};
}
var twice = multiplier(2);
console.log('twice:'+twice(5));
And in console I get this output:
factor:2
number:5
twice:10
I understand what a closure is meant to be, but I do not understand how the variable number, that by my knowledge I expected to be undefined, get the value 5.
My reasoning is the following:
When I call the function multiplier(2) the local variable factor is assigned the value 2, so the first output is correct.
But when it reaches the line return function(number){ it shall assign number undefined, since no value has been previously assigned to such a name.
So it shall crash at all, and not doing correctly the output I got.
May anyone help me understand why calling twice(5) it get the output
number: 5?
Thank you all, excuse me again If i did not post the question in the right way, feel free to modify anything to make this question more intelligible.
return function (number) { ... } returns a function. number is not a variable, it's a function parameter. The same way that factor in function multiplier(factor) is a parameter. It is neither undefined nor does it cause anything to crash either.
In essence, multiplier(2) returns this function:
function (number) {
console.log('number:' + number)
return number * 2;
}
...which you assign to twice, so twice is now the above function.
I think the key thing that you're missing here is that the returned function acts just like any other function. The function isn't entered until it's called.
return number * factor;
doesn't run until you call twice. It's just like how
console.log('factor:'+factor);
doesn't run until you call multiplier. The body of the function isn't entered until the function is called. number doesn't have a value until twice is called, but the code that uses number also doesn't run until twice is called.
But when it reaches the line return function(number){ it shall assign number undefined, since no value has been previously assigned to such a name.
Here's the misunderstanding. Remember: In Javascript, almost everything is an Object. Some will say that many things that you interact with regularly (strings, numbers, booleans (Notice how I put these types/primitives/words first letter in lowercase. I usually use uppercase for Classes and lowercase for primitives)) are primitives, not objects. This is true, but for the purpose of this thread let's consider (almost) everything is an Object.
Let's get back on this sentence you wrote:
when it reaches the line return function(number){ it shall assign number undefined
Here's the issue: when it reaches the line "return function(number){}", it actually returns a function, which is an object.
It does not execute this function, it only declares it, and returns it, as an Object.
You could have wrote "return 666", it would have returned an Object. A Number.
Let's continue.
Your variable "twice" now contains a function. Guess which one. This one:
function(number){
console.log('number:'+number)
return number * factor;
}
Remember, you've declared it and returned it in only one statement:
"return function(number){...}"
Your "twice" variable is now equivalent to a named function you could've declared this way :
function twice(number){
console.log('number:'+number)
return number * factor;
}
Yes, functions are Objects, named functions are like named variables, and variables can be functions.
You can call it this way for example: twice(9), or this way: twice(5).
That's what you've done.
Now let's answer your question:
why calling twice(5) it get the output number: 5?
Because:
var twice = function(number){
console.log('number:'+number)
return number * factor;
}
And you've executed "twice(5);" which in turn executed console.log this way:
console.log('number:'+5);
As far as I've understood, in your "function multiplier()", you do not want to return a function but rather the result of this function itself. I advise you to read about IIFE (Immediately-invoked function expression).
With this you will be able, in only one statement, to:
- declare a function
- execute that function
- (and eventually return its result)
Have fun playing with Javascript. Javascript is great, only when you know what's going behind.

First return value of function undefined?

So I have a function here that returns an element of an array for every function call. It keeps from returning the same element twice by checking against another array that used elements are pushed to.
The problem is that I keep getting "undefined" back when I run it the first time. If I make more than one console.log call, the calls after the first one return an element.
I'm thinking it has to do with my first "if" statement, but I'm not sure. Does an empty array return a length property of 0? Is that the issue in my "if" statement?
I appreciate all the help, thanks in advance.
var fortunesList = [
"A",
"B",
"C",
"D",
];
var usedFortunes = [];
var getFortune = fortunesList[Math.floor(Math.random()*fortunesList.length)];
function fortuneCookieGenerator(getFortune) {
if (usedFortunes.length == 0) {
usedFortunes.push(getFortune);
}
else if (usedFortunes.length > 0) {
for (i = 0; i < usedFortunes.length; ++i) {
if (usedFortunes[i] == getFortune) {
getFortune = fortunesList[Math.floor(Math.random()*fortunesList.length)];
i = 0;
}
}
usedFortunes.push(getFortune);
}
return getFortune;
}
console.log(fortuneCookieGenerator());
console.log(fortuneCookieGenerator());
console.log(fortuneCookieGenerator());
console.log(fortuneCookieGenerator());
getFortune is undefined because you have that as an argument to fortuneCookieGenerator but you pass in nothing. After the first time your function gets called usedFortunes.length is greater than 0 triggering the else branch and you assign a new value to getFortune and return that.
You might also benefit from these JS debugging guides: Creativebloq, MDN, Google and MSDN.
Your function has the next signature
function fortuneCookieGenerator(getFortune)
which means that you can pass an argument, getFortune to it. Now, when you want to call the above function, you use the next;
fortuneCookieGenerator()
Which means that you're calling the function without passing an argument. So, at the first call, the getFortune is not defined yet. Also, the variable usedFortunes is still empty. As result of this,
usedFortunes.push(getFortune);
from the first if block gets invoked. You're pushing an undefined variable to the array. Once that gets done, the program proceeds to
return getFortune;
Which returns undefined.
At the second call, you still don't pass an argument, but the variable usedFortunes now is not empty. So it will execute the else if block. There, you have
getFortune = fortunesList[Math.floor(Math.random()*fortunesList.length)];
which initializes the variable. As result of this,
return getFortune;
holds something, you don't receive undefined anymore. That's why you are getting undefined at first call, but not at second and further calls.
getFortune() will be undefined if the condition is not true, so I think you need to add else part also to intialize it.
Do this at first:
console.log(fortuneCookieGenerator(getFortune));
Or,
function fortuneCookieGenarator(getFortune){
.......

Sorting behavior on passing function vs. passing anonymous closure

Problem and Question
I have a small application that asynchronously gets JSON data from a server, formats it into a table, and allows the user to perform some simple operations on the table (sorting, filtering, etc.).
One of the sorting functions accesses DOM elements in the previously-generated table (definition given below).
var SORT = function(){
var my = {};
// public methods
my.byName = function(sign){
(!sign) ? sign=1 : 1;
var T = $("#resultArea").find("tbody");
var R = T.children("tr");
R.sort( function(a,b){
var an = $(a).attr("data-name");
var bn = $(b).attr("data-name");
return sign * an.localeCompare(bn);
});
R.detach().appendTo(T);
}
...
return my; }();
When specifying it as a callback for an element the user can click on, I have two formulations.
$("#sort-button").click(SORT.byName); (pass function as argument)
OR
$("sort-button").click(function(){SORT.byName();}); (pass anonymous closure that calls the function)
The first option fails, but the second works. Here is how it fails on a test case with 536 rows to be sorted:
Former row 2 (which precedes row 1 in alphabetical order) is moved to position 268.
Former row 269 is moved to position 536.
Former row 536 is moved to position 2.
I have tried and failed to construct a MWE that fails in the same way (will update question once I succeed). Questions are: What went wrong? Why does using the anonymous closure work?
Update
An earlier version of the snippet had been sanitized to remove the parameter sign and the line at the start (which would set sign to 1 if it evaluated to false or was undefined), the idea being that by passing sign=-1 as a parameter, a descending sort could be done. When I removed sign from the definition in the live code, the problem went away.
So I found that the offending line is (!sign) ? sign=1 : 1; When replaced by the more transparent if(sign !== undefined){sign=1;} the problem goes away. I think what it does is that it sets global sign to one on the first pass, then on the second pass, sign is defined so it returns 1, and the function ends (only one pass having been completed).
Then why does this error not crash the sort on the anonymous closure approach?
As you found out, the problem comes from that sign parameter. When you pass a function as the event handler and call SORT.byName() without arguments, you'll get sign=1 and everything is as expected. But when you pass the function directly as the handler, it will get called with the Event object as its argument. Suddenly you have an object in your sign variable, and multiplying that with a number will yield NaN (an invalid result for a comparison function), which completely messes up your sort.
When replaced by the more transparent if(sign !== undefined){sign=1;} the problem goes away. I think what it does is that it sets global sign to one on the first pass…
Nope. There is no global sign variable at all. And I guess you actually wanted if (sign === undefined) sign = 1;. Which wouldn't work as well when passing in events, so you might want to use if (!Number.isFinite(sign)) sign = 1;.
Without seeing more of your code I can't really tell what's going on. The snippet you have posted seems alright. Regarding your question, there is a subtle difference when you pass SORT.byName vs. sending it wrapped in an anonymous function. Specifically, it is the value of this in the byName function when it is executed.
When you do click(SORT.byName), you are sending a direct reference to the function, which means that when it gets called, the value of this is whatever the jQuery handler for click sets it to be when before it calls your callback function; usually this is a reference to the element that fired the event.
However, when you do click(function() { SORT.byName(); }), the value of this in byName is the SORT object (but this in the anonymous function is still whatever jQuery sets it to). This is because here you're invoking the function explicitly as a method of the SORT object.
So if your sort functions rely on the value of this and assume it to be the SORT object, you can run into issues.
Here's some code that demonstrates this behavior:
var obj = {
field: 10,
method: function() {
console.log(this);
}
};
// The first argument to apply sets the value of "this"
function call(f) {
f.apply("not this", []);
}
call(obj.method); //logs "not this"
call(function() { // logs obj
obj.method();
});
Searching through the DOM and sorting is not fun. You would be better off keeping some state, sorting, and then appending the new results to the DOM after you remove the old like so.
var myNumbers = [
[1,'one'],
[4,'four'],
[2,'two'],
[6,'six'],
[3,'three'],
[8,'eight'],
[7,'seven'],
[5,'five'],
[10,'ten'],
[9,'nine']
];
myNumbers.sort(function(a,b){
if (a[0] > b[0]) {
return 1;
}
if (a[0] > b[0]) {
return -1;
}
return 0;
});
var T = $("tbody");
var R = T.children("tr");
R.detach()
After that you can prepend your results in a loop like you addElemnt function but a loop instead.

Properties of an empty array

I am a novice in nodejs and javascript .I am learning nodejs. I have a doubt here . I came across a node js code , which I was unable to understand :
jumble = {} ;
jumble.debug = false;
jumble.start = function (guid, callback) {
}
I am still wondering , what does jumble.start do when its just an empty array, any help /links would be appreciated Please
There are no arrays here.
jumble = {} ; creates a object and assigns it to jumble
jumble.debug = false creates a property called debug on the object and assigns the value false to it.
jumble.start = function (guid, callback) {} creates a property called start on the object and assigns a function to it.
You could call that function with jumble.start(1,2), but it wouldn't do anything since the function doesn't have anything between { and }.
I don't know node.js but, I know it is similar to javascript.
So, first of all, jumble is an object and not an array, as you think it is.
debug is a property of jumble object which has been assigned the value of false.
start is a function of jumble object which is obviously empty as it does nothing when called by doing jumble.start(3,4).

How does this javascript work, functional programming

In going through some exercises about functional programming, and returning a closure, came across this example, and cannot figure out how it works:
function invoker (NAME, METHOD) {
return function(target) {
var targetMethod = target[NAME];
var args = _.rest(arguments);
return function() { return targetMethod.apply(target, args);});
};
};
The test:
var rev = invoker('reverse', Array.prototype.reverse);
var result= _.map([[1,2,3]], rev);
The output should be:
[[3,2,1]]
but i cannot prove it.
Specific questions:
Why is args:
0,1,2,3
Why is console.log(arguments):
[object Arguments]
How to print out the result, to see [[3,2,1]].
When I print out "result", I get:
[object Object]
After correcting the issues in the code (missing semicolons or too many) there appear to be a few closures that get created throughout the script's execution.
First:
function invoker (NAME, METHOD) {
return function(target) { // In the example this is rev
// Begin Scope1 (closure)
var targetMethod = target[NAME]; // NAME is trapped here in Scope1 (defined outside of this function) when the function is executed!
var args = _.rest(arguments);
return function() { //
// Begin Scope2 (closure)
return targetMethod.apply(target, args); // target and args are trapped here in Scope2 (defined in Scope1's function) when the function is executed!
};
};
}
The invoker does nothing until it is called and the first closure (Scope1's that is) does not get created until invoker is actually invoked:
var rev = invoker('reverse', Array.prototype.reverse);
After rev has been initialized by invoker, it has become a variable that contains a function that accepts a single named argument (called target) that when called will look for a function called NAME (in this case 'reverse') on whatever object target is.
When rev is actually called it also returns a function that, when called, will call the target method (reverse in this case) on target (the array passed in). But rev hasn't been called until the next line is run:
var result= _.map([[1,2,3]], rev);
Here is what is happening here: _.map's purpose is to take a list of items and apply a function to each item in this list. The final result will be a new array with the transformed values in it. The line above passes to _.map a list with exactly one item in it; an array. It also passes to _.map a function to transform each item in that list; in this case rev.
So _.map is called and it calls rev on the only item in the list, our [1,2,3] array. The function rev has the effect of returning yet another function that, when called, will remember NAME, target and args. This function now resides inside the first element of the array variable 'result'.
Now for your questions:
The output should be:
[[3,2,1]]
but i cannot prove it.
In the test code there is no output, only a final variable called result. What I think you are looking for is that somewhere in the end there should be a reversed array. You can verify that the original array has been reversed with the following after the call to initialize result:
alert(result[0]().join());
Why is args:
0,1,2,3
args is really a red herring here; _.map passes 3 arguments to its iterator function. The current value (in this case the array [1,2,3], the key or index (in this case 0) and the original list itself. When _.rest is called on arguments, it slices off the first item leaving us with an array containing 0 and [[1,2,3]]. When reverse is called on this array (args) it ends up returning an array that looks like [1,2,3,0] which is these two items reversed. My tests never showed 0,1,2,3. Why is args a red herring here? Because when reverse is called reverse doesn't take any arguments and so args is ignored. If this was a different function on a different object you would probably encounter issues because of the call to _.rest.
Why is console.log(arguments):
[object Arguments]
Because you are basically calling toString() which will print the object's type.
How to print out the result, to see [[3,2,1]]. When I print out
"result", I get:
[object Object]
You can use:
console.log(result[0]().join());
UPDATE: Here is the jsbin link with working code: http://jsbin.com/aYECIDo/5/edit?html,css,js,output
Use console.log and a modern browser with actual development tools.. like chrome, or firefox+firebug. Then you should be able to see in the console the result. Or, when you print it out in HTML, serialize it using JSON.stringify. Example: document.write(JSON.stringify(result)).
That should write out a JSON representation of what you're seeing.
Regarding the [1,2,3] look at the .apply function in the MDN.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply
Apply takes a first argument of scope, and an array of arguments to cause the function to be called with.

Categories

Resources