javascript - How to make this code work? [duplicate] - javascript

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 9 years ago.
Code gives me:
A
B
C
When I click on A B C it always shows me the last one "vodka".
I want "martin" (for A), "lindsay"(for B), "vodka" (for C)
Please help me on my example.
myArray = [
{
letter: "A",
brand: "martin"
},
{
letter: "B",
brand: "lindsay"
},
{
letter: "C",
brand: "vodka"
}
];
var list = '';
for (var i = 0; i < myArray.length; i++) {
list += "<br>" + myArray[i].letter;
new_info = myArray[i].link;
(function(new_info) {
$(this).click(function(){ //this - refers to A or B or C
$('#box2').text(new_info);
});
}).call(this, myArray[i])
}
$('#box1').append(list);

Edit:
I said I wasn't going to write your code for you... well, I did: this fiddle does exactly what you're looking for. I solved the issue with context (this), closure issues and implied globals. It still needs a lot of work, but the fiddle shows what everybody has been saying: $(this) does not, cannot and will never point to a string constant like "A", or "B".
Sorry to say this, but your code is full of problems, but I will address the specific issue you're asking about here.
Inside the loop, you're assigning a click handler that, basically looks like this:
function()
{
$('#box2').text(new_info);
}
Where new_info is a variable that is declared in a higher scope. So far, so good. The problem is, the function object you're creating doesn't have its own copy of whatever value that variable (new_info) happened to hold when that function was created. Instead, the function references that variable. So when any of those functions is invoked it $('#box2').text(new_info) will be resolved to $('#box2').text("whatever value new_info holds when function is called"), not $('#box2').text("whatever value new_info was holding when function was created"). You can give each callback access to a copy by simply adding a second function to your code:
$(this).click((function(currentNewInfo)
{
return function()
{
$('#box2').text(currentNewInfo);
}
}(new_info)));
What I'm doing here is creating a function, that takes an argument, and calling it immediately. I pass new_info as an argument, so the value of currentNewInfo will be what new_info holds at that time (aka a copy)
The function I called (IIFE - or Immediately Invoked Function Expression) returns the actual callback. In this callback, I don't reference new_info, but the argument of the IIFE: currentNewInfo.
Because each function has its own scope, that variable is enclosed (hence the name closure), and cannot be accessed or altered from outside. The only thing that can still access the currentNewInfo variable is the function the IIFE returned.
Perhaps you are worried about name-conflicts (each callback you create uses references currentNewInfo), but that's not the case: each callback was created by a separate function, and therefore has access to a different scope. It's not possible to have a name conflict between scopes that don't access each other... Just to make things really simple to understand:
Where /\ and /\
|| ||
is return function() is scope of IIFE
So closures have access to a function's scope after it returns. That scope has precedence when it comes to resolving an expression to a value. To understand this better, here's a similar diagram to show you how JS resolves expressions:
Where each pink "outer environment record" is a scope of a function (closure scope of a function that has returned already or function currently being called). The last environment will either be the global object, or null (in strict mode). That's all there is to it.
Honestly, closures are tricky to get your head round at first, but once you grasp what I tried to explain here, they're great fun.
Check this link I can go on to explain the use cases and benefits and ways nested closures work, but I'd end up writing a book. The link I posted does a great job at explaining how closures work using rather silly drawings. It may seem childish, but they actually helped me a lot when I was trying to grasp the concept of lambda functions, closures and scopes out-living a function-call. The diagrams above are taken from the page I linked to, which explains the concepts a bit more in-depth, but I still think the simple, crude drawings are pretty self explanatory.
Other issues:
As someone pointed out: "What are you expecting this to reference". Looking at the snippet, this will just reference the global object (window), attaching the same/similar event handler to window simply doesn't make sense if you ask me.
Global variables are evil, implied globals even more so. I can't see new_info, nor myArray being declared anywhere. The way JS resolves expressions is a tad unfortunate and falls back to creating global variables, without so much as a peep:
var bar = 666;//global, always evil
function createGlobal()
{
var local = 2;
foo = bar * local;
}
createGlobal();
Let's look at foo:
JS is in createGlobal scope: var local is declared, and assigned 2.
foo is used, and assigned bar*local
|| || \\=>found in current scope, resolves to 2
|| ||
|| \\=>found in global scope, resolves to 666
||
||
||=> JS looks for foo declaration in function scope first, not found
||
||=> moves up 1 scope (either higher function, or global scope)
||
\\=>Global scope, foo not found, create foo globally! - hence, implied global
\\
\\=>foo can now be resolved to global variable, value undefined
Excessive DOM queries: your event-handler callbacks all look like so:
$('#box2').text(new_info);
This ($('#box2')) is actually the same as writing document.getElementById('#box2'). Which is practically English. Think about it like this: each time the client clicks on $(this) - whatever that may be, you're accessing the DOM, and scanning it for an element with a given ID. Why not do this once and use a reference kept in memory to change the text. That saves countless DOM queries.You could use a variable, or (in light of what I explained about closures), a closure:
var list = (function(box2, list, i)
{//list & i are arguments, so local to scope, too
for (i = 0; i < myArray.length; i++)
{
list += "<br>" + myArray[i].letter;//<-- don't know why you use this
//new_info = myArray[i].link; no need for this var
$(this).click((function(new_info)
{//new_info is closure var now
return function ()
{//box2 references DOM element, is kept in memory to reduce DOM querying
box2.text(link);
};
}(myArray[i].link));//instead of new_info, just pass value here
}
return list;//return string, assign to outer variable
}($('#box2'), ''));//query dom here, pass reference as argument

Related

Bind a changing variable in function, I want a name

I have somethings like:
var i = 0;
var func = function(){
console.log(i);
};
func(); //0
i++;
func(); //1
I want to have the second console also output '0',
so I change the program like:
var i = 0;
var func = (function(_i){
return function(){
console.log(_i);
};
})(i);
func(); //0
i++;
func(); //0
I know how it works, but is there any name or terms to describe such mechanism?
I've been calling this mechanism "breaking the closure" though I've had arguments in the past with people who insist on calling this technique "closure".
The reason I call it "breaking" closures is because that's what you're doing.
The classic place where you see this is in solutions for closures in loops:
var hellos = [];
for (var i=0; i < 10; i++) {
hellos.push(
(function(j){
return 'hello ' + j
})(i)
);
}
The problem is caused by a closure being created between the outer variable and references to that variable in the inner function (technically the variable is called a "free" variable rather than a closure, "closure" technically refers to the mechanism that captures the variable but in the js community we've ended up calling both things closures). So closure is the cause of the problem. Since the problem is caused by a closure being created I've started referring to the solution as "breaking the closure".
Note that even though some people call this a closure and you may google for "js closure" to read more about this technique it is ironically not a closure. What it is is simply how functions pass arguments (there's a whole side-argument about how javascript actually pass arguments to functions which you can read here: Why are objects' values captured inside function calls?). Javascript is a fairly strict pass-by-value language in the same way C is a strict pass-by-value language (C can ONLY pass by value).
When you pass a reference in js (objects, arrays) the function will not get the original reference but rather a copy of the reference. Since it is a reference it obviously points to the same object as the original reference so it is easy to mistakenly believe that javascript passes by reference. But if you try to assign a new object to the passed-in reference you will notice that the original reference does not change. For example:
function foo (x) {
x = [2,3];
}
var y = [1,2];
foo(y);
console.log(y) // prints [1,2] so foo() did not change y
It is this mechanism that is responsible for breaking the association between the outer variable (in your example that would be i) and the inner variable (_i in your example). The name of this mechanism is simply function calling (well, technically it is a subset of function calling - it is how arguments are passed to function calls).
So to recap:
I personally call it "breaking the closure"
Some people call it "closure" even though it is not a closure (the closure is what they want to avoid instead).
Side note: I realize that the original example is about a global variable but in javascript global variables are just a special case of closures - closures are ALWAYS created when you define a function, it's just that when there's no outer function the outer scope is simply the global scope.
It's called a closure. You can read more about them here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
When passing in a primitive type variable like a string or a number, the value is passed in by value. This means that any changes to that variable while in the function are completely separate from anything that happens outside the function.
if the variable in the scope is not declared, it will search the outer scope, until find it, or to the window scope. if not find, it will the variable global.

Nested Functions, Closures and Scope

I've been trying to wrap my head around scope, specially closures.
I know that there are many posts about the topic, and I've been reading a lot. But most places refer to the topic as advanced, and use terminology that is relatively difficult to grasp. I would like to be absolutely sure that I've got the basics right, so that I don't go venture into the more intricate topics with a wrong idea of how functions really work.
So... I picked a basic function, and would really like for someone to tell me if what I think its happening under the hood is what is actually happening.
This is the code:
function sum(a) {
return function(b) {
return a+b
}
}
console.log( sum(1)(sum(2)))
(I know that it's not actually do the sum, I was tweaked with it, to try to understand what was going on in each step.)
So, my main doubt was why A was 1, and not 2. I reached the conclusion that the closure is created, as soon as function(b)is created to take sum(2) as an argument, right after being returned by sum(1). Therefore, by the definition of closure, I'm assuming that at the time the function is created it also saves the lexical environment (in which a = 1). Is this right?
I've made a diagram of the steps.
here is what happening
1) If a function returns a function and that returned function gets called immediately that's called currying (A functional programming term). You have mixed currying and closure both concept in this example.
2) First your sum(1) part gets called . which will return function(b) {return a+b} (lets refer it as #1st) , but with It will keep alive a as 1 for the for the context of #1st only.
3) As the functions argument is a function call itself then that argument part will get called . e.g sum(1)(sum(2)) , here sum(2) part will get called and it returns function(b) {return a+b} (lets refer it as #2nd), also It will keep alive a as 2 for the context of #2nd only (closure).
4) Now we are immediately invoking #1st with #2nd as parameter with that currying syntax - #1st(#2nd)
5) so our a is unallocated variable and have value 1, b variable has a value function(b) {return a+b} . As we are concatenating these two, so final output is 1function(b) {return a+b}
N.B. - a) In case you wanted a sum of a+b and not that weird output just change your final line as console.log(sum(1)(2)) . b) In case you noticed closure a having value of 2 in the function referred as #2nd is never getting used anywhere but alive .
Whatever facility we use to transport an inner function outside of its lexical scope, it will maintain a scope reference to where it was originally declared, and wherever we execute it, that closure will be exercised.
In the next function you will see how the greet will use a variable salute declared inside the greeting function even when this is no longer being called, this is called a Closure.
function greeting(name) {
var salute = "Hello "; // This is a closure
return function() {
console.log(salute + name);
}
}
var greet = greeting("Dave");
greet(); // Hello Dave
You can learn a lot more about closures in the Kyle Simpson's book series You Don't Know JS but for this particular topic check You Don't Know JS: Scope & Closures. He uses a simple and up to the point language to explain difficult concepts like this one.
When sum is called it creates a scope. Within this scope there's the formal parameter a and an inner, anonymous function, which is immediately returned. This anonymous function is a closure, because it captures the scope of its enclosing function (sum). Consequently this inner function has access to a.
Now we come to the point that confuses you apparently: The inner function gets only a copy of sum's scope, not a reference to the original one. That means if we return from sum and thus eliminate its scope, this copy remains unaffected (a of the inner function remains 1). Further function calls of sum with different arguments don't affect the closure either.
Conclusion: A closure can exist longer than its enclosing function.
Technically speaking a of sum is stored in the stack, whereas the captured a of the closure is stored in the heap and is thus independent of the lifetime of sum.
By the way, what you're doing here is called currying. Instead of calling sum with several arguments you call it procedurally, with a single argument per invocation:
sum(1, 2); // multi argument form
sum(1)(2); // curry form

Javascript Closures and variable scope when function call ends

I have read this excellent piece:
How do JavaScript closures work?
But I still have questions...
StackOverflow tags defines "Closures" as "A Closure is a first class function that refers to (closes over) variables from the scope in which it was defined. If the closure still exists after its defining scope ends, the variables it closes over will continue to exist as well".
When my functions end with a return, do all variables defined within them get deleted and memory allocation made free? It appears to me that conditions exist when one could answer yes or no.
Yes, I know memory is plentiful and free but that is not my question.
Think of an intranet based application which ajax's data back and forward during a working day. As data is received by the client, massaged, and no longer required, it can be dispensed with. Poor programming technique could result in a build up of data no longer user or required (or worse, data being used that is out of sync).
Reading the piece on closures above tells me that some variables within a function can still be referenced from outside the function scope. I am guessing that I will need to re-read the closure document several times as perhaps I've not fully understood it.
Can someone share an example on where a variable continue to exist?
And... Do I gain any benefit if, at the begining of each function I declare my variables, and prior to using a "return true;" if I reassign the variables a value of null?
All help appreciated...
num will exist within a function outside of IIFE c which returns a
var c = (function() {
var num = 10;
var a = function a(n) {
console.log(n)
return n * Math.random()
};
return a.bind(null, num)
}());
var res = [c(), c(), c()];
console.log(res)
When you return true from a function you don't have a closure. You have a closure when you return a function from a function, like this:
function makeAdder( firstNumToAdd ){
return function( secondNumToAdd ){
return mainNumToAdd + secondNumToAdd;
}
}
var add3 = makeAdder(3);
var seven = add3(4);
In the above example, the variable firstNumToAdd, although is scoped to the function makeAdder is always accessible to the inner function, even though the function exited after executing the line var add3 = makeAdder(3);
Please correct me if I am wrong, but I don't think that
some variables within a function can still be referenced from outside the function scope
is true.
Closures remember the context of a function call and bind the relevant variables (i.e. this, etc) to the closure's scope. If that is correct, then calling the closure again would cause the old variables' values to get garbage collected and you wouldn't have to worry about memory waste or out of sync data.
obj = {
func: function(){
var test = 'preserved value';
this.func2 = function(){
console.log(test);
};
}
};
obj.func();
obj.func2(); //'preserved value'
obj.func = undefined;
obj.func2(); //'preserved value'
As you can see, even after completely blowing away the original scope (func) the enclosing scope retains the test var.

Are functions set before variables in the javascript 'creation phase'?

I am doing the Udemy course Javascript: Understanding the Weird Parts right now, and I just learned about the creation phase and the execution phase that occurs when the interpreter interprets the JS.
I have a question, but I will first show you the code I am playing with:
http://codepen.io/rsf/pen/bEgpNY
b();
function b () {
console.log(a);
}
var a = 'peas';
b();
If I understand correctly, in the creation phase, the variables and functions are 'set', meaning they are given spots in memory. The variables are all given the placeholder value of undefined. Then in the execution phase, the engine executes the lines starting at the top. When b() is first called, 'a' still has the placeholder value of undefined, then 'a' is given its initial value of 'peas', b() is called again and this time 'a' has the value of 'peas'.
In my mind, one of two things has to be happening here. Alternative 1: In the creation phase, all variables are set before functions. This means that when a memory space for the function b() is created, the function includes a's value of undefined (because the 'a' memory space was already created with the value of 'undefined'). Alternative 2: the functions and variables are set in the lexical order they are in (in this case, b is created before a), and when b is created, the 'a' reference somehow means that the function is listening for any possible creation of an 'a' memory location, and when later the 'a' location is actually created, the reference refers to that spot.
Am I on the right track with either of these scenarios?
You can think of it like this.
Your original code:
b();
function b () {
console.log(a);
}
var a = 'peas';
b();
is actually executed like this:
var a;
function b () {
console.log(a);
}
b(); // log undefined because a doesn't have a value yet
a = 'peas';
b(); // log peas because a has a value
Basically all the variable and function definitions are hoisted at the top of the enclosing scope.
The order doesn't really matter because the code inside the b function doesn't get executed until you actually call the function.
If I understand correctly, in the creation phase, the variables and functions are 'set', meaning they are given spots in memory.
I would not use the term set for this--it usually is used to refer to a variable being set to (assigned) a particular value. I also would not use the term "spot" or "memory"--we don't need to worry about these internals. It's clearer just to say declared.
I also don't really like the use of the term "creation phase", which is both non-standard and confusing--what is being created, exactly? I would prefer the term "compilation".
The variables are all given the placeholder value of undefined.
To be precise, I would not say they "have the value of undefined", but rather "have no value", or "are not defined". undefined is not a value held by a variable which has not been assigned to yet; rather it's a state, which causes the variable to evaluate to the undefined value when accessed.
Alternative 1: In the creation phase, all variables are set before functions.
Yes, although again it's going to be confusing to use the word "set". Say, "all variables are declared before functions". This is the process of hoisting.
Alternative 2: the functions and variables are set in the lexical order they are in (in this case, b is created before a), and when b is created, the 'a' reference somehow means that the function is listening for any possible creation of an 'a' memory location, and when later the 'a' location is actually created, the reference refers to that spot.
No. The function does not "listen" to anything. It just executes when you tell it to.
Is this important?
Not really. It falls into the category of arcana. So we clog up our brains with rules like, variables hoist this way, function declarations hoist some other way, let has yet some other hoisting behavior. In practice, almost all style guides will call for you to declare variables at the top of the function, and linters will warn you if you don't (or can be configured to do so). This immediately eliminates all variable hoisting issues.
Some people like to put internal functions at the bottom of their function, and that works fine since, if it's a function declaration (ie function foo() { }) the whole thing (including the definition) is hoisted. If it's a function expression being assigned to a variable (ie var foo = function() { }), then it's a variable, and we already decided to put those at the top of our function--see paragraph above.
In general, if your program depends on hoisting behavior, it's written badly. If you need to understand hoisting behavior to understand how the program works, it's written badly.
To summarize, all you really need to learn is one rule: put variable declarations (and their initializations) at the top of your function. Then you don't have to worry about hoisting at all.
(There are some exceptions, such as declaring a variable inside a for statement, as in for (var i...), which is fine, assuming i is not being used for anything other than the index of the loop.)
For some reason, people learning JS seem sometimes to focus on these oddities--such as "why does " " == false or something. I would suggest instead focusing on the how to think about your problems, and break them down, and writing nice clean code that just works, and that you and other people can maintain without worrying about the arcana. I've been writing JS for many years, and cannot remember the last time I encountered a problem related to hoisting.

Javascript clears a variable after there is no further reference it

It is said, javascript clears a variable from memory after its being referenced last.
just for the sake of this question i created a JS file for DEMO with only one variable;
//file start
//variable defined
var a=["Hello"]
//refenence to that variable
alert(a[0]);
//
//file end
no further reference to that variable, so i expect javascript to clear varaible 'a'
Now i just ran this page and then opened firebug and ran this code
alert(a[0]);
Now this alerts the value of variable, If the statement "Javascript clears a variable after there is no further reference it" is true how come alert() shows its value.
Is it because all variable defined in global context become properties of window object, and since even after the execution file window objects exist so does it properties.
Of course the variable HAS to be kept around in this example - after all, you keep the ENVIRONMENT it has been defined in around. As long as you COULD still access it is has to be kept, so if you can make this test and it ever fails - the JS interpreter is "kaputt".
Do this instead:
(function () {
var a = 1;
}());
// and NOW, at THIS point there is nothing any more referencing "a"
Of course, from out "here" you cannot test that - you'd have to look at the internal memory structures of the JS interpreter/compiler (today in the days of V8 it's more like a "interpiler" or "compreter" aynway).
In addition though, like all garbage collecting (GC) languages, the memory is not freed immediately but depending on GC strategy used by the particular implementation of Javascript, which also takes current memory usage and demand into account. GC is a costly operation and is delayed, if possible, and/or run when it does not take away CPU resources from the real app.
By the way, slight variation:
(function () {
var a = 1;
//empty function assigned to global namespace,
//in browsers "window" is the global object
window.example_function = function () {};
}());
In THIS example the result is the same as in yours: as long as you view that page the memory for "a" is NEVER released: the function assigned to property example_function of the global object still exists, so all of the environment is was defined in has to be kept! Only after
delete window.example_function
which deletes that property - which in the end is a pointer to the (empty) function expression - from the global object, could variable "a" be released. Also note that "a" is not even used by that function, see Google and search for "lexical scoping", one of the most defining properties of the Javascript language.
And even more fun:
Had I written
//define a variable in global namespace
var example_function;
(function () {
var a = 1;
//empty function assigned to global namespace,
//in browsers "window" is the global object
example_function = function () {};
}());
I could not use "delete" to remove it, in fact I could not ever release it. That's because in the first example example_function becomes a new property of the global object (emphasis), while in this last example it is a variable, and "delete" works with object properties only. (I used "windows.example_function" in the earlier example, but without the "window." it would have been just the same, example_function would have been created as property in the global object. Only the "var" statement creates variables.)
Is it because all variable defined in global context become properties of window object, and since even after the execution file window objects exist so does it properties.
Yes. You would either have to close the window, or explicitly remove a from the window properties.
A side effect of your script is that there's a property name "a" defined in the global object ( window ), so there is actually still a global reference to a.
(function()
{
var a = 12;
alert(a);
})();
If we wrap the declaration of a in self-executing function like here, a will be inaccessible after the function has exited.
Yes, although you can mitigate this behavior by declaring and acting on your variables within the scope of a function:
( function myfunc(a){
var b = 100;
alert(a); // 200
alert(b); // 100
}(200));
alert(a); // undefined
alert(b); // undefined
Referencing a variable does not mean using it in some manner. As long as there is at least one reference to the variable which can still be accessed, it has to be kept in memory.
Looking at your example, the following line has no effect on whether the variable gets cleared or not. Even if a wasn't being used anywhere, it would still have been kept intact.
//refenence to that variable
alert(a[0]);
Although an object may be created inside a function, its lifetime may extend beyond the function itself. The only thing to remember is whether there are still any valid references to the object in question. Consider this example,
(function() {
var a = ["Hello"];
var copy = a;
a = null;
setTimeout(function() {
// a: null, copy: ["Hello"]
console.log("a: %o, copy: %o", a, copy);
}, 2000);
})();
The variable a is created inside an anonymous function, and another variable copy is referencing it. a is set to null right after, but we still have 1 reference to it from copy. Then we create a timeout which makes another reference to the same variable. Now even though this anonymous function will go out of scope after it executes the setTimeout, we still left 1 reference to it in the timeout function. So this copy variable will still be intact when the timeout function is run.

Categories