Confused by the interaction between function parameter, closures, and chain of visibility

The code in question:

function addLinks () { for (var i=0, link; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function (num) { return function () { alert(num); }; }(i); document.body.appendChild(link); } } window.onload = addLinks; 

My problem is that the returned function is a closure, and the num variable is a global variable every time the function executes num , should contain the current value that replaces the old one, and should be updated automatically with this value everywhere. But this does not happen - when I click on each link, I get a different value. Why is this happening?

+4
source share
5 answers

Think about it: what if you had three links, for example:

 <a href="#">0</a> <a href="#">1</a> <a href="#">2</a> 

You want them to display their number when you click on them, so do the following:

 var links = $('a'); for (var i = 0; i < links.length; i++) { links[0].onclick = function () { alert(i); } } 

At first glance, you expect that, for example, since you assigned a click handler to the first link when i = 0 , it will warn 0 when you click on it. However, when you click on it, it will warn 3 .

You said it yourself, your code creates a closure. What the above code does is that it assigns a function handler to the click event for each link. Each of these function handlers maintains a reference to the variable i (note: not the current value!).

The moment you assign a function handler, it does not actually evaluate what value i (because it does not need it). When you press, aha, this is when he checks that i is the value and warns about it.

When you click the link, the for loop will be long, with i = 3 and what your click handler warns about.

+1
source

num closed by an anonymous function. function (num) { return function () {}}(i) passes i as an internal function and returns a new function based on any value of i .

If you want the clickback callback to always warn about the maximum value of i , this is actually even simpler:

 link.onclick = function () { alert(i); } 

function (var varname) is just not valid syntax.

+2
source

Please look at (i) after your function. This type of label is for self-charging functions only. It is as if you are setting link.onclick = number, while it expects a function. You can simply use the following.

  link.onclick = function (event) { event.preventDefault(); alert(i); }; 

Note that click functions by default accept "event" as a parameter. Make sure you call the preventDefault () method of the event, otherwise it will bubble into the DOM and trigger the postback due to the nature of the binding element.

0
source

You did not explain where the num variable came from or how it is used. I assume you want to warn the current value of i . The click handler takes an event object as a parameter, so I would try it like this:

 function addLinks () { for (var i=0; i<5; i++) { var link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function (event) { alert(i); }; document.body.appendChild(link); } } window.onload = addLinks; 
0
source

This is strange and inconsistent with what I thought of closing. With a single change (in the first version of addLinks in the question):

 link.onclick = function (num) 

to

 link.onclick = function () 

You get the expected result, that is, the actual value of the global variable num warned at any time when the link is clicked.

This is likely due to the way the interpreter stores the sphere variables referenced in the closure when it encounters this closure. When a variable refers to a closure, it searches for the closest occurrence of that variable to move up from the current area.

While in the first case it is defined as a parameter (for a function that is called several times after the declaration), it has a different value each time, so each value is "remembered" by each closure.

In the second case, the only discovery found is in the global scope, as a result of which the actual num value is used regardless of which handler is called.

0
source

All Articles