The next step in mastering JavaScript closures is being able to “get” or “set” a private variable.
In Part I of this series: JavaScript Closures – The Absolute Basics, I discussed wrapping one function with another, which produces a closure. When that returned function is assigned to a variable, as long as that variable is alive, it (a function) has access to the context of the function that wraps it. This means that the outer (or “wrapping”) function can contain a private member, but the wrapped function has access to it. In that post, the example code consisted of a function that returned the private member.
Let’s take this one step further: we want to be able to “get” and “set” that private member in real time. Consider the following code:
In Example # 1, we first create a global variable named “drink” that is set equal to “wine”. Our reason for doing this will become apparent in a moment. Next, we have a variable named “foo”, which is set equal to an anonymous function. Here is where the “closure” stuff comes in: That anonymous function (i.e. “foo”) returns an object literal. That object literal contains two properties: “getDrink” and “seDrink”. Both are anonymous functions.
After the declaration of the anonymous function “foo”, we create a variable named “bar” that is equal to the return value of “foo” (i.e. we execute “foo”, and set the variable “bar” equal to that). Because “foo” returns an object literal, it is almost as if we simply did this:
1
2
3
4
varbar={
getDrink:function(){returndrink},
setDrink:function(drnk){drink=drnk;returndrink;}
};
But that does not completely represent what is going on here. Although “bar” is, in fact, equal to an object literal that has two anonymous functions as members, that object literal was returned by a function (and that is a critical detail). Because that object literal was returned by a function, the two anonymous functions that are members of the object literal have access to the function that returned them. Because they will execute in the context of “foo”, they have access to the private scope of “foo”.
Ok, so what does this all mean?
Remember when we created a global variable named “drink”, and set it equal to “wine”? Well, in Example # 1, when we say: “console.log( drink )”, and the output is “wine”, that is because in the global context, “drink” equals “wine”. But there is another variable named “drink” in play. That variable is in the private scope of “foo” and it is set equal to “beer”.
Hang in there, we are getting to the good stuff now…
In Example # 1, when we say: “console.log( bar.getDrink() )” and the output is “beer”, that is because “getDrink()” has access to the private scope of “foo”, and in the private scope of “foo”, “drink” is equal to “beer”. Next, when we say: “console.log( bar.setDrink(“juice”) )”, we are mutating (i.e. changing) the value of the variable “drink” that exists in the private context of “foo”. This is because:
“bar” was set equal to the value of whatever “foo” returned
“foo” returned an object literal
The object literal that “foo” returned contains a member: “setDrink()”
“setDrink()” has access to the variable “drink” which is in the private scope of “foo”
We change that private variable “drink” to “juice” using “bar.setDrink()”
If you run the jsfiddle link for Example # 1, you will see this all in action (make sure you have your JavaScript console open). Once the code has run, type the following in your JavaScript console: “console.log( bar.getDrink() )” the return value will be “juice”.
Summary
There is no such thing as a wasted moment when it comes to understanding closures in JavaScript. This is a powerful feature of the language. In this post, we discussed getting and setting the value of a variable that exists in the private scope of a function that returned an object literal. Stay tuned for more to come on this topic which does, at times, seem complex, but is more than worth the effort, and is an important tool in your JavaScript belt.
Demystifying this topic is one of the most important steps towards truly understanding the JavaScript language
It is a little difficult to get your head around JavaScript closures without a basic understanding of scope. I will not attempt to tackle that subject in any kind of detail here. But let’s at least consider this thought: JavaScript functions always (always) retain a reference to any variables that are in-scope when they are defined.
I know that sounds a little nerdy, but it is important to remember. if you are not quite sure what that means, take a little time to explore the concept of scope in JavaScript, then come back to revisit the topic of closures.
Assuming you are comfortable with the concept of scope, think about a function that is defined in the global scope. There is not much going on there because the global scope is the outer-most scope. But what about when a function is defined inside another function? That is where the power of closures starts to take place. When a function is defined within another function, it has access to any variables that are in-scope at the time of definition.
Example # 1
1
vardrink="wine";
var foo = function(){ var drink = “beer”; return function(){ return drink; }; }; var bar = foo(); console.log( drink ); //wine console.log( bar() ); //beer
In example # 1, we first create a global variable named “drink” and set it equal to “wine”. Next we have a function “foo”, that returns another function. When we say: ‘var bar = foo()’, we are assigning the value that foo returns to bar.
JavaScript functions always (always) retain a reference to any variables that are in-scope when they are defined.
Since foo returns a function, then bar is now a function. Because the function that has been assigned to bar is defined inside of foo, it has access to foo. This means that in our case, bar returns a private variable that lives inside of foo. That variable inside of foo named “drink”, has been set to “beer”. So, in the global context, “drink” equals “wine” and in the context of foo, “drink” equals “beer”.
The end result is that when we pass the variable “drink” to the console, it is “wine”, because in the global scope, “drink” is equal to “wine”. But when we pass “bar()” to the console, we get “beer”. That is because “bar()” is a function, it returns a variable named “drink” and because “Bar()” was defined inside of foo, it returns the first “drink” it finds, which is private to “foo()” and it is equal to “beer”.
At the most basic level, this is how closures work.
Summary
There is much more to talk about with regards to JavaScript closures. But for those of you scratching your heads, just trying to get the basics down, I hope this was helpful.
A video tutorial about JavaScript Closures
Helpful links for getting started with JavaScript Closures
jQuery makes it super easy to get a reference to a collection of DOM elements. The jquery.each method allows you to execute a function against each one of the elements in the collection.
Solving problems is one of jQuery’s best qualities, and the beauty of the jQuery.each method is that it solves a very common problem: how to iterate a collection of DOM elements. Now in order to work through this task, one might be inclined to set up a for-loop. This approach is not at all wrong; in fact, on some levels it makes perfect sense. The thing is, in tackling it this way you run into a few avoidable problems. First, there is a lot of boilerplate code. In other words, to set up the for-loop you would need a counter variable, which we’ll call “i”. And since we might want to iterate a collection of DOM elements more than once, we’d need to make the “i” variable private, which means using a function to create private or “local” scope. Also, 80% of our for-loop would be repeated code. So, you get the picture… our problems are mounting, and they most assuredly are avoidable. So, here’s where the beauty of the jQuery.each method comes into play: it provides abstraction for creating a for-loop. This means that we need only provide the collection and a callback method that we wanted executed for each iteration of the loop.
The jQuery.each method is the go-to tool when you need to iterate a collection of DOM elements. Let’s say you have a bunch of elements in the page. Maybe that bunch is “every <a> tag” or “every <li> inside of the <ul> with the class sales”, or each <div> element that is a child of <div class=”members”>.
Here is how you would create a reference to each of those collections
jQuery will return a collection with one or more members. But how do you iterate over that collection and “do something” to each one? You can accomplish this by chaining the .each() method to the return value, and of course, pass a callback to that method.
jQuery.each Method – Basic Syntax
In the above example, where you see “selector”, that represents a CSS-like query such as “p” or “#some-id p img”, etc., that you would pass to jQuery. Now you can see that we have passed a callback function to the each() method. And inside of that callback, we would take care of any tasks that are specific to the elements over which we are currently iterating.
So, for an example, we will create a click-event handler for each <li> inside of a <ul>. Here is the markup we will work with:
With that markup in mind, consider the following code:
Example # 1
Notice that in Example # 1 we use $(this). Now just in case you are not familiar with this pattern, $(this) equals “the current element”, and it happens twice in our code. The first instance of $(this) on line # 2 refers to the element that is currently being iterated over (i.e. the current “UL LI”). The second $(this) on line # 3 represents the element that was just clicked. This is because we want to change the color of the element that was just clicked to red.
From a pseudocode perspective, here is what we have done:1- For each <li> that is inside of a <ul>, add a click event handler
2 – In the click-event handler, we say “If you click me, make my text red”
Example # 2
In Example # 2, we change the logic a bit so that only an <li> with the class “workday” is returned in the collection, which means that the “saturday” and “sunday” <li> elements do have a click event handler assigned.
Here is the JsFiddle link for this example: http://jsfiddle.net/WHkkA/. Simply remove the .workday class from the CSS selector to see Example # 1 work.
Summary
The jQuery .each() method is used to iterate over the members of a jQuery collection. There is definitely more fun stuff that can be done with this method, but this is just a very basic overview of what the method does and how to use it.
Important Note: Try not to confuse this with the jQuery.each() method. That is a similar concept, but more of a general-purpose iteration method that is a static method call to the jQuery object, not a method of a jQuery collection.
Use the Date() constructor to create a unique query string; ensure each GET request is not cached
The other day, I was working with a customer whose iPad app was consuming an HTML page.
I was making changes to the CSS, yet was not seeing them in the iPad app. I kept adding a new query string to the URL of the CSS file, which forced the iPad app to download the updated CSS file. So, growing a little tired of changing the URL to the CSS element, I wrote a little cache buster script, and that was the end of the fiddling around.
This is very easy to do, so let’s look at an example.
In this example, we instantiate the Date() constructor, and get a reference to the time. Since this number is incremented by one, it will always be unique. We then create a new element, and set the required attributes: “rel”, “type” and “href”. The href has a query string that includes a reference to the time, so we have a GET request that is essentially different from the last one we made, and the next one we make will be different from this one, and so on.
Run this in your JavaScript console, and as long as you have a file name “style.css” in the same directory as your HTML file, you will see a new element appended to the <head> element. You can, of course, take the same approach with any resource that requires a web address such as a JavaScript file, an image, and so on.
Summary
Cache busting can ensure that often-changing files such as CSS and JavaScript always get downloaded by the client’s browser (i.e. never cached). It’s just a simple technique, but it can keep you from pulling your hair out.
The little-known JavaScript Option() constructor allows you to avoid the verbose syntax of creating DOM elements
We all love jQuery. Among the many awesome qualities of this library is the ability to easily create DOM elements and place them in the document without the normally verbose syntax of native JavaScript.
But there is a little-known feature of JavaScript that allows you to create option elements with fairly minimal effort. This feature is the Option() constructor. The syntax is simple:
Get a reference to a form element
Instantiate the constructor and associate the returned object with the form element
During instantiation, pass-in the following arguments: 1) the text shown in the page [string], 2) the value of the control [string], 3) if it is the default selection [true/false] and if it is selected [true/false]
In Example # 1, we have a simple form that includes a select control. In the markup there are three options: “Monday”, “Tuesday” and “Wednesday”. When the JavaScript runs, the following actions take place:
We get a reference to the select controls (“w”)
We delete all of the option elements (w.length = 0)
We create an array of objects, each with two properties (“d”)
We loop through the array and for each array element, dynamically create a new select element, using the object’s “text” and “val” properties. In each case the last two arguments: “false”,”false” mean that this new element will not be the default, nor will it be selected.
And that’s it!
Summary
The little-known Option() constructor can be used to create new HTML option elements. So, depending on how you choose to approach this, you can write some pretty efficient code that side-steps the normally verbose syntax of document.createTextNode(), document.createElement(), and document.appendChild() methods.
Helpful Links for the JavaScript Option() constructor
You may be finding conflicting information about associative arrays in JavaScript. Well, the answer is quite simple… and then things start to get a little odd
If you are frustrated because you have been getting different answers on this subject, I”ve got good news and bad news. The good news is, the answer is simple: associative arrays are not supported in JavaScript. Arrays in JavaScript are index-based. Plain and simple, end of conversation. But the bad new is, it’s not quite the end of the conversation. The reason for this is that the following code actually works just fine:
1
2
3
4
5
6
7
vararr=["mon","tues","wed"];
arr["drink"]="beer";
arr["music"]="jazz";
console.log(arr[0]);//mon
console.log(arr["drink"]);//beer
[insert shrugged shoulders here] “…ok Kevin, so what’s the problem ?”
The problem is: you do not have an array with five elements. You have an array with three elements, and two properties.
Huh?
Yup, this is the part where JavaScript array objects behave in an unexpected way. But hang in there, it’s actually kind of cool once you understand what is happening.
Arrays are Objects
Arrays in JavaScript are numerically indexed: each array element’s “key” is its numeric index. So, in a way, each element is anonymous. This is because when you use methods of the Array object such as array.shift() or array.unshift(), each element’s index changes. So, after using array.shift(), array element # 2 becomes array element # 1, and so on. (array.pop() and array.push() may change the length of the array, but they don’t change the existing array element’s index numbers because you are dealing with the end of the array.)
All this is to say that in a JavaScript array, each element can only be identified by an index, which will always be a number, and you always have to assume that this number can change, which means that the whole “key/value” idea is out the window (i.e. no associative arrays in JavaScript. Sorry.).
OK smarty-pants, if you can’t have associative arrays in JavaScript, why does this work: arr[“drink”] = “beer” ?
Glad you asked. This is because in JavaScript, arrays inherit from Object(). Whether you use an array literal or instantiate the array constructor, you are creating an object, plain and simple. Consider the following:
Example # 1
1
2
3
vararr=newArray(3);
vararr=[];
vararr=["mon","tues","wed"];
In Example # 1, we create an array in three different ways. The first line creates a new array with three elements, but they are all undefined. The second line creates a new array, but it is empty, with no elements (this is an array literal). The third line creates an array literal, but we provide values for the elements as we define the array. In all three cases, you are creating an instance of the Array() constructor, which inherits from Object(). So, these are ALL objects.
Example # 2:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
vararr=[];
console.log("the length of arr is: "+arr.length)// 0
console.dir(arr)//there are no child objects
arr[0]="mon";
arr[1]="tues";
arr[2]="wed";
arr["drink"]="beer";
arr["music"]="jazz";
console.log("the length of arr is: "+arr.length);// 3
console.dir(arr);
0->"mon"
1->"tues"
2->"wed"
drink->"beer"
music->"jazz"
In Example # 2, we create an array literal, but it is empty. (var arr = []; works just fine, but it is an empty array.) When we check the length property and try to inspect the object with console.dir(arr), we can clearly see that it is empty. Then we add elements to the array, and add named properties (e.g. arr[“drink”] = “beer”). But when checking the array’s length property, and inspecting the object, we can see that the actual “array” part of the array still has only three elements (i.e. “music” and “drink” are NOT elements in the array), and that “music” and “drink” are properties of the array object.
Arrays are Objects with their own special “array-ish” properties
What is happening, is that the Array() constructor returns an instance object that has some special members that other objects such as Function() and Date() do not. So when your code says: arr[“drink”] = “beer”you are simply adding a new property to your object, which happens to be an array, and that property has a name of “drink”, and you have assigned the value of “beer” to it.
You could have easily assigned a number, an object, an anonymous function, or one of JavaScript’s other data types. This property “drink” has no connection to the elements in the array. It does not increase the value of the array’s “length” property, and it cannot be accessed via the array-ish methods such as pop() or shift().
Let’s see what happens when we take advantage of this object’s “array-ness.”
Example # 3:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
arr.push({
name:"bart simpson",
phone:"555-1212"
});
arr.push(function(){
console.log('i am an element of the array "arr", that
happens to be an anonymous function');
});
arr.testMe=function(){
console.log('i am "testMe", a property of the array "arr",
that happens to be an anonymous function');
};
console.log("The length of arr is: "+arr.length);
console.dir(arr);
The output forexample#3would be:
The lengthof arr is:5
0->"mon"
1->"tues"
2->"wed"
3->Object{name="bart simpson",phone="555-1212"}
4->function()
drink->"beer"
music->"jazz"
testMe->function()
OK, so things are gettin’ pretty weird, right? Yep, but it’s all cool stuff, and at the end of the day, it’s no big deal. It just illustrates the way objects work in JavaScript. Let’s run it down:
First, we use the JavaScrpt Array() object’s push() method to dynamically add an element to the array. It just so happens that this new element is an object literal, with two properties. Its index becomes 3.
Next, we use the same push() method to dynamically add another element to the array. This new element is an anonymous function. Its index becomes 4.
Next, we create a new property for our array called “testMe”. This new property happens to be an anonymous function. It has NO index, because it is NOT an element in the array, just a new property that we have added.
Next, we use the console to check the array’s length property, which is now “5”, and we inspect it.
Dont’ forget it is an array, but it is also sill an object; Array() inherits from Object(). When inspecting the object, we see that our two uses of push() did, in fact, add two new elements to the array; one is an object, the other is an anonymous function. We also have “testMe”, wich is a new property of arr.
Ok, so what happens if we attempt to access the two functions that we added? Oh, they will run just fine, but remember: one is an element in the array, the other is a property of the arr object. So we access them differently:
Example # 4:
1
2
arr[4]();
arr.testMe();
The output for Example # 4 would be:
1
2
3
4
5
iam an element orthe array"arr",
that happens tobe an anonymous function
iam"testMe",apropertyof the array"arr",
that happens tobe an anonymous function
In each case, we are simply executing a function. It’s just that in the first case, that function is an element in the “arr” array. So, we have to access it using its index, which happens to be “4”. This can get tricky fast, and care should be taken in doing this kind of thing, but just to illustrate a point: array elements in JavaScript can be of any data type. In the second case, we access the function by its name “testMe”, because it is a PROPERTY of the array, not an element. Much easier, and there are no issues, because “testMe” will always be “testMe”, so it’s easy to access.
Summary
This is all pretty overboard. I mean, don’t we usually want this: var arr = [“mon”,”tues”,”wed”] ? Well, yes. Most of the time we do. But the point of this post is two-fold:
JavaScript does NOT support associative arrays. Period.
Arrays are objects, so properties can be added any time. Those properties can be any data type.
In JavaScript, arrays are best used as arrays, i.e., numerically indexed lists. The great thing is that those elements in the array can be of any data type. Index # 0 can be a string, # 1 can be an object, # 2 can be an anonymous function, and # 3 can be another array.
But once you start doing things like this: arr[“drink”] = “beer”, you are swimming in somewhat dangerous waters. Unless you really know what you are doing, you will get odd behavior because arr[“drink”] is NOT a numerically indexed “member” of the array (it is not an array “element”), and does NOT have the relation to arr[0] and arr[1] that you may think it does.
As soon as you start doing things like: arr[“drink”] = “beer”, it is time to consider putting this key-value pair in an object literal. You don’t have to, but it’s a better way to manage your data, and the approach leverages JavaScript’s strengths, instead of wrestling with the somewhat odd nature of it’s underlying architecture.
P.S.: If you really wanna see some odd JavaScript array behavior, try this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
vararr=[];
vararr=["mon","tues","wed"];
arr["drink"]="beer";
arr["music"]="jazz";
arr.push({
name:"bart simpson",
phone:"555-1212"
});
arr.push(function(){
console.log("anonymous function as element");
});
arr.testMe=function(){
console.log('anonymous function as property');
};
for(varprop inarr){
console.log("Prop: "+arr[prop])
}
The strange output of this one is for another discussion : – )
Helpful links for associative arrays in JavaScript
The replaceWith() method provides a way to completely remove an element and put another in its place
Most of the time, jQuery is used to add click event handlers to DOM elements, and there’s nothing wrong with this. In fact, jQuery is so helpful in this context, it’s hard to argue against using it for your event handling / delegation. But just be aware… there are other tasks that come up, and some of them can get rather messy. One example is replacing one DOM element with another. Now this may sound simple, but with vanilla JavaScript, this kind of work can get pretty tedious. Normally, I recommend learning how to do things with vanilla JavaScript that you would want to do with jQuery, but there are times when this kind of wheel reinvention becomes a bad idea.
So, this is where the jQuery replaceWith() method comes in; it allows you to chop out one piece of the page and replace it with another. You simply specify the original section of the DOM as well as the new chunk, and then jQuery takes care of all the work. And what makes this method so helpful is the expressive syntax; on a high-level, it’s a simple as A.replaceWith(B). You really do have to thank the folks from jQuery, for packing a great deal of abstraction into this one method. If you don’t believe me, go ahead and try this yourself using just vanilla JavaScript. I think you’ll find that it’s pretty tedious.
Example # 1
In example # 1, we have attached an event handler to the element with the id: “foo”. When clicked, that element is removed from the page, and replaced with a piece of markup defined in a string. Yes, it’s that easy, and there are certainly more interesting things you can do with this jQuery method.
Summary
Replacing one section of the page with another piece of markup is quite easy with the jQuery replaceWith() method. The syntax is very straight-forward and if you are already familiar with jQuery, there are quite a few possibilities.