Closures in JavaScript

In JavaScript you sometimes need so called "closures" to encapsulate scope.

Lets say you want to make a pattern for each texture:

// Create patterns
for(var i=0; i < textures.length; i++) {
	textures[i].onload = function(i) {
		pattern[i] = ctx.createPattern(textures[i], 'repeat');
	}
}

The code loops the texture array and when each texture has loaded a pattern is created.

But there is a problem! Once a texture has loaded, the for loop has already finished and the variable i passed to the onload function will always be textures.length!

To solve this you need to use a closure. It might look something like this:

// Create patterns
for(var i=0; i < textures.length; i++) {
	textures[i].onload = (function(index) {
		return function() {
			pattern[index] = ctx.createPattern(textures[index], 'repeat');
		};
	}
})(i);

This can be hard to understand. But it's possible to rewrite the code to make sense!

What the closure does is to create a function and then pass variable i to it, that becomes the local variable index

You can rewrite it like this:

for(var i=0; i < textures.length; i++) {
	createPattern(i);
}

function createPattern(i) {
	textures[i].onload = function() {
		pattern[i] = ctx.createPattern(textures[i], 'repeat');
	}
}

So next time you need to make a closure, put the code that needs to run right away in a function!

Async Closure

var button = document.createElement("button");
button.appendChild(document.createTextNode("Click me"));
document.body.appendChild(button);

button.onclick = function click() {
	button.appendChild(document.createTextNode(" more!"));
}

Even though the click function is async (run later) it will have access to the button variable!


Written by Johan Zetterberg April 16th 2015.


Follow me via RSS:   RSS https://z├Ąta.com/rss_en.xml (copy to feed-reader)
or Github:   Github https://github.com/Z3TA