Jump to content

a simple closure example


skaterdav85

Recommended Posts

I am trying to understand closures and I have created an example which needs it, but I just don't know how to implement it. You can see my JS bin file here:http://jsbin.com/ekoqi4/editBasically there are 5 links, and when you click each one, i want it to alert its position in the collection. Right now each link alerts the number 4 because it is alerting the the last value of the counter variable i. Anyone know how to implement a closure here?

  <a href="#">One</a>  <a href="#">Two</a>  <a href="#">Three</a>  <a href="#">Four</a>

window.addEventListener('load', function () {  var anchors = document.getElementsByTagName('a'), i, len;  for(i = 0, len = anchors.length; i < len; i++) {	this.onclick = function () {	  alert(i);	};   }}, false);​

Link to comment
Share on other sites

oops i just noticed that i used this incorrectly and it should have been anchors. Anyways, here is the updated jsbin file:http://jsbin.com/ekoqi4/3/editJSG, do you know how to solve this problem using a closure?

window.addEventListener('load', function () {  var anchors = document.getElementsByTagName('a'), i, len;  for(i = 0, len = anchors.length; i < len; i++) {	anchors[i].addEventListener('click', function () {	  alert(i);	}, false);   }}, false);​

Link to comment
Share on other sites

Enclosing the variables whose values keep changing (as in a for loop) leads to quasi-intuitive results, I think.

for(i = 0, len = anchors.length; i < len; i++) {   something.onclick = function () {	  alert(i);   };}

You might think that i would be enclosed in the function with the value it had when the function was defined, and that this would be the case with each iteration. But it is not. Unique copies of i are not enclosed. Only one copy of i exists, and that's what gets enclosed. The value that gets alerted in this system will be the value of i when it was last referenced, and that will be true for each anonymous function. So in this case, the value of i will always be anchors.length, no matter which element is clicked.BUT! Try this experiment:

function Ob () {   for (var i = 0; i < 3; i++){	  this[i] = function () {		 alert(i);		 i++;	  }   }}var O = new Ob();O[0](); // alerts 3 as expectedO[1](); // alerts 4

Link to comment
Share on other sites

Dave, are you just trying to learn about closures? I think I just explained why a closure really won't work in this situation. For the same reason that's why jsg showed you a different strategy, which is to bind the value of i to something stable.If you're goal is to learn about this thing rather than solve a problem, then I think what you've learned is which kind of problem a closure really won't solve.

Link to comment
Share on other sites

DD, interesting approach. I guess that would work too. i was curious about closures since they keep coming up in several JS books and YUI Theatre videos and I didn't get them until now actually. So I found a pretty good explanation on Stack Overflow here and the example was pretty similar to what I was trying to do and I created something that works and what I think is a closure.new JS bin file

window.addEventListener('load', function () {  var anchors = document.getElementsByTagName('a'), i, len;  for(i = 0, len = anchors.length; i < len; i++) {	anchors[i].addEventListener('click', (function (i) {	  return function () {		alert(i);	  }	}(i)), false);   }}, false);​

My example works now, and from what i've read, a closure simply put seems like a way to bind a particular instance of a variable to a function and the way it is done here and in the example on Stack Overflow is by executing a function that returns a function (Function Factory as they call it).EDIT: My definition is probably very wrong. I can see what is going on here but I don't know how I would explain what a closure is to someone haha

Link to comment
Share on other sites

I had to look at that a couple of times to see how it worked. I'm embarrassed to say I've never seen it before. Kind of clever. It is exactly what you say it is: a self-executing function returns a function with the correct value of i enclosed in it because the value has been copied into a variable that is unique to that function. (That's a mouthful.) It actually makes a little more sense if you change the identifiers a little:

anchors[i].addEventListener('click', (function (newVar) {   return function () {	  alert(newVar);   }}(i)), false);

This makes it clear that i itself is not being enclosed. Instead, i is being passed by value into newVar. In turn, newVar is enclosed by the innermost function, and newVar has a stable value because it really is a unique variable with each iteration.(This was just an illustration. Using the same in the different contexts keeps the intention clear.)

Link to comment
Share on other sites

DD, interesting approach. I guess that would work too. i was curious about closures since they keep coming up in several JS books and YUI Theatre videos and I didn't get them until now actually. So I found a pretty good explanation on Stack Overflow here and the example was pretty similar to what I was trying to do and I created something that works and what I think is a closure.new JS bin file
window.addEventListener('load', function () {  var anchors = document.getElementsByTagName('a'), i, len;  for(i = 0, len = anchors.length; i < len; i++) {	anchors[i].addEventListener('click', (function (i) {	  return function () {		alert(i);	  }	}(i)), false);   }}, false);​

My example works now, and from what i've read, a closure simply put seems like a way to bind a particular instance of a variable to a function and the way it is done here and in the example on Stack Overflow is by executing a function that returns a function (Function Factory as they call it).EDIT: My definition is probably very wrong. I can see what is going on here but I don't know how I would explain what a closure is to someone haha

hah, that is pretty slick.
Link to comment
Share on other sites

it is an interesting approach by using a function's local scope to preserve an instance of i for each iteration. this was just one example, but do closures usually involve the execution of a function to returning a function with unique values bound to its function arguments?

Link to comment
Share on other sites

A simple closure, the kind I generally use, does not look like this example. It's more like:

function obConstructor (x, y, z) {   this.calc = function () {	  return (x + y) / z;   }}var ob = new obConstructor(2, 4, 9);alert(ob.calc() );

Kind of a silly example, but you get the idea.

Link to comment
Share on other sites

  • 3 weeks later...

i know it's an old thread but just wanted to say I had a need to do just this kind of thing involving closures and callbacks, and thank goodness I remember this. Thanks for your example in particular DD, it worked pretty nice as a model

scene.setupCannedButtons = function(){  var canned = [];  var basePath = "images/buttons/home/";  var utilObj = root.AVJS.TVV.utils;	  for(var i = 0, l = root.TVV.mosaics.length; i < l; i++){	var mosaic = root.TVV.mosaics[i];	if(mosaic.canned && mosaic.name != "Showcase"){	  canned[canned.length] = {		"name" :  mosaic.name	  }	};  };	  for(var j = 0; j < 3; j++){	var name = canned[j].name.toLowerCase();	var pathOn = basePath + name + "_on.png";	var pathOff = basePath + name + "_off.png";	onClick = function(name){	  var mosaic_name = name.toUpperCase();	  this.click = function(){		scene.loadCannedMosaic(mosaic_name);	  };	};	var func = new onClick(name);	utilObj.setupOnOffClick(scene['img_canned' + (j+1)], pathOn, pathOff, func);  };};

and the utility using the callback

(function($) {	  $.TVV.utils.setupOnOffClick = function (button, onImg, offImg, onClick) {	button.loadImage(offImg);	button.onFocus = function (previous) {	  button.loadImage(onImg);	};	button.onBlur = function (next, oldIndex) {	  button.loadImage(offImg);	};	button.onClick = onClick.click;  };}(root.AVJS));

thanks! :)

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...