What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
Underscore.js Fundamentals
by Craig Shoemaker
Learn to take control of JavaScript collections, arrays, functions and objects all while improving the performance of your code and making your JavaScript more readable and expressive.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Introduction
Introduction
Hello and welcome to Underscore.js Fundamentals on Pluralsight. This is Craig Shoemaker and during this course, I'll take you step-by-step through the Underscore library. So that when our time together is complete, you'll be ready to use Underscore in everyday development scenarios. First, I'll take you on a sightseeing tour through the vast Underscore API, where I'll show you dozens of code samples where you can see Underscore in action. Along the way, we'll spend some time uncovering some of the concepts and algorithms supported by Underscore and finish up with some integration exercises where you'll see how Underscore is used in some real-life situations. Well, thanks again for joining me. Let's go ahead and get started.
Why Underscore.js?
This course is based off of Underscore version 1.4.4 and you can visit the official website at underscorejs.org. Now one of the best parts about the website is the annotated source code, where you can learn not only a lot about how Underscore operates, but also a few lessons about JavaScript along the way too. Underscore is an open-source component of DocumentCloud and you can visit them at documentcloud.org. Now, maybe you're familiar with Underscore and you're looking to sharpen your skills or perhaps you've heard a lot about Underscore and are wondering what this library is all about. So, in order to answer the question of why Underscore, let's first consider a few other questions about some tasks that you've probably done in JavaScript in the past. Have you ever wanted to apply a function over each item in a collection? Now our old friend the four loop, is reliable, but he insists that you do a lot of repetitious work if you want to do similar actions over and over again. What about taking an array and manipulating it or transforming it in some way? Again, it's not rocket science, but JavaScript doesn't inherently have anything that makes this a trivial task. Filtering can be painful sometimes, depending on the type of data that you're working with. How would you like an easy way to filter object collections and arrays? Beyond that, what about easy ways to group, to count those groups, sort, and shuffle collections, all within an easy-to-use library? Moving beyond collections, wouldn't it be nice to have a mechanism to know that a function was called only once on your page? And when working with objects, how nice would it be to be able to easily extract out the keys of an object or even maybe just the values? What about performance? It'd be nice to have a few tools available to you that can drastically improve the performance of your code. So for all these reasons and so many more, which you'll soon see in depth, are why you may want to add Underscore to your project.
What is Underscore.js?
But, what exactly is Underscore? Well, it's a JavaScript library that provides a series of functional utilities that make working with collections and arrays and objects and functions much easier when compared to the native support found within the language. Underscore requires no dependencies and in fact it falls back to the native implementations when available. Notice that if the environment supports ECMA Script 5, implementations for forEach and map, reduce, keys, bind, and even more, those native implementations are used in favor of what's implemented in Underscore itself. Just so that you can get an idea of how this works, let's take a look at the implementation of the each function in the annotated source on the Underscore website. Near the very top of the source for the Underscore library, you'll see some variable declarations here that are very important in the library. Notice the variables for nativeForEach and nativeMap and on down the line. They're set equal to the native implementations for forEach, and map, reduce, reduceRight, and on and on. So, as functions are implemented within Underscore, they'll be some checking going on to see if the objects that are passed in to the Underscore functions include the native implementation found in the environment. And if that native implementation is found, it just defers to that functionality instead of anything implemented within the library. Let me take you down to the function so you can see what I'm talking about. So, here's the definition for the each function. Now, the first thing that you'll notice is it sets each equal to _.each and _.forEach. This is done to create aliases for this function. People coming from different environments and using different libraries know this functionality by different names and so here, it's being set to each and forEach. The arguments for this function are an object, an iterator, and the context. Now, I'll show you exactly how this works when I get into the demos for each, but for this function you can pass in either a regular JavaScript object or an array. Also, you'll pass in an iterator. The iterator is a function that is executed against each item that's iterated over within the each function. And the context sets the value of the this pointer, which is used inside the iterator function. So, right off the bat, the first line checks to make sure to see that the object or the data that's being passed in to this function has some sort of value. So, if obj = null, it's simply calling return and returns execution back to the caller. The next if statement looks at the object and compares the implementation for a member called forEach with the nativeForEach. Now, you could create a JavaScript object with a function called forEach and it could be something completely different than what's implemented in the native environment. So here it's checking to make sure that whatever object's being passed in, if that forEach implementation matches the nativeForEach, then it'll go ahead and use that implementation by calling it, passing in the iterator and the context. If that evaluates to false, so basically there's no nativeForEach implementation, then this function is going to try to determine whether or not it's looking at an array or an object. Now, this odd-looking code here is executed in order to try to determine whether or not it's looking at an array or an object. Now, arrays have an integer value for the length property. So if that length property exists, in this +obj.length, there's some type coercion. So, +obj.length to something that doesn't have an integer value for length will return not a number. If it has a value, then it'll return the same value as obj.length. So if it's an array, and this is Underscore's way of determining whether or not it's an array, this will return true. Otherwise, it will return false. And in both cases, it simply calls the iterator function that's passed in to it either for each item in the array or for each key in the object. So, the bottom line to looking at all this is to show you that if there's a native implementation that's found within the environment, the appropriate functions will use that native implementation. Otherwise, the stated behavior of the function is implemented right here, within Underscore.
Supported Environments and Libraries
Now, while you might at first just think that Underscore is only appropriate for the browser, it's also used widely in Node development and can be used in Window store applications and most likely just about anywhere you use JavaScript. Further, Underscore works well with many of the different JavaScript libraries out there. While jQuery shines at DOM manipulation, Underscore adds a set of functional ability, which works well to compliment jQuery development. Beyond that, even the popular library Backbone is built on top of Underscore. In fact, a quote from Underscore's website describes Underscore as "the tie to go along with jQuery's tux, and Backbone.js's suspenders." Now speaking of Backbone, if you're interested in digging into Backbone more, Liam McLennan's course on Backbone.js Fundamentals will prove to be a great resource for you. The nice thing about Underscore is that just about every function exposed in the library is available via either a functional or object-oriented paradigm. And while this is true, even the methods that you call still accept functions as parameters and behave very functional in nature. Let me show you what I mean. I'll soon take you through how the map function works, but let's take a moment to consider this code. Let's say you have an array of names and you want to run the map function against the array. You can call the function directly off the Underscore library or you could pass the input of the function to the library and then call the desired function from there. The end result of the two styles are identical and for most cases the difference between the two is a preference. In both styles you're passing in an iterator function, which is applied to each item in the collection. You'll see this type of approach used often in Underscore.
How to get Underscore.js
Now, before we get started with the demos, there's a few housekeeping things I want to go over with you. Like, how do you get Underscore.js to begin with? So, the first stop obviously is the website, underscore.js.org. From there you can go to the Downloads section and as it says here, you can Right-click and "Save As" in order to get the Development and the Production Versions. As you dig into the Development Version, there are a lot of comments in here for you. So, whether you have the website available to you in order to have the API documentation or if you just have the Underscore Development Version, both will be a great resource to you as you're learning Underscore. Obviously there's the Production Version. You can see that the Minified, Gzipped version of it is only 4KB. You can also go over to GitHub where you can have access to the full source code, but something that's even more interesting if you see the link to the tests that it has, and there's 575 tests all available, you can dig into those tests here on GitHub. And you'll notice here if we go into collections, you can see each one of the tests that are shown on the screen there for the each function. Again, another great resource for you to use as you're learning Underscore.js.
Summary
There are a few other courses in the Pluralsight library that make a good companion to this course. For those new to JavaScript, Liam McLennan's JavaScript Fundamentals is a great place to start. And for those a bit more seasoned in JavaScript development, Dan Wahlin's Structuring JavaScript Code is a must watch for any JavaScript developer. Underscore is a JavaScript library that has functional utilities that truly make your life easier when it comes to managing collections, working with objects, and using JavaScript really for all it was intended to be. Next up, we'll begin to dig into the collections module of Underscore and see how each and map and filter and where and so many more of these functions will help speed your development along and make your code more expressive and easier to maintain.
Collections
Introduction
The Collections functions found in Underscore can work with JavaScript objects or arrays and make working with Collections often a trivial task. Now before I dive in to the explanation of the code of the each function, there are a few things I want to point out about the code viewer that I'll be using throughout this course. In the upper-left-hand corner you'll see a star with an E5 next to it. That's a flag to show you that this function is associated with some native functionality found in ECMA Script 5. So, if that native implementation is available, Underscore will defer to that functionality. Also, next to it you'll see an icon for CONTEXT. You can pass in an object, which will be bound to the function for this pointer. I'll show you how that works in a second, but I won't have a demo for every time the context is available. So you'll just see how it works and then every time you see that flag at the top, you'll know that you have it available to you in any of the functions that it appears. Lastly, when you see this i icon, you'll know that the code that's in here is for informational purposes. In other words, it doesn't run and in fact, if you try to run it, you'll get a little reminder as well. Alright, now let's dig in to the each function. First, I'm showing you how to use the each function with an array of values. So, here I have some names. Now I want to iterate over each of those names and do something interesting with it. So first, I'll call the each function and pass in the array of names. Then from there I can declare an iterator function, which will be called each time one of the values is looped through within the array. Let's run it and see what happens. So here, the element is Craig, index is 0, and the list length is 4. So if you take a look at the signature of the iterator function, you'll see that the element is the element within the array, the index is the current index found in the array as it's looping through, and then if you need to get back to the original data you can take a look at the list argument. Now, I'm using this log function to log things out as individual list items within my results pane over here. And so, I thought it might be a good idea to show you what that looks like. So as I'm logging content out to the results, the first thing I want to find out is whether or not the contents that I'm passing in is an array. If it's an array, then I'll recursively go through and iterate using the each function to log the contents out to the results window. So every time I'm logging something to the results window, I'm just creating a new list item. You'll see that log function a lot within this course, so I just wanted you to have an idea of how it works. Sometimes I'll pass in arrays, sometimes I'll pass in just individual pieces of content. And so that's how it knows what to do based off of what I'm passing to it. Next, let's take a look and see how each behaves when dealing with an object. So here, I have a JavaScript object with firstName of Craig and lastName of Shoemaker. When I call each against author, the iterator now has a signature of value and key. So you'll notice that I'm able to print up the key and value. The list portion of the arguments here is undefined because I'm not working with a list, I'm working with an object. Now I'll show you how you can pass in context and how that works. So when I'm working with an array you'll notice here I ran it and I've got Hello there, John, Craig, Dan, and Elijah. So as I call each, I'm passing in people.names because this object here has an array nested inside of it and it also has a function called getMessage. Once again, the iterator has the signature of element, index, and list and from here, I can call log and then this.getMessage passing in the element. Because I passed people down at this point, after the iterator, as the last argument to the each function that then will bind the people object to the this pointer within the iterator. So since I did that, when I call this. I'm able to get to the getMessage function. Without passing in a context like that, the this pointer would not point back to people, but rather it would point back to the iterator function itself. So, you'll find lots of different ways of how this can come in very handy by passing in a context within the each function. Now let's take a look at what that looks like when you're dealing with an Object. I'll Run this here and you can see that I've got Hello! Craig and Hello! Shoemaker. I've got two objects in play here. First, I have the author, which is just the data object and then I have a messenger object. It's got a function for getGreeting and getMessage. So, I'll iterate over that author object by passing in author and then create my iterator. Again, I have value and key, and then I can call this.getMessage. That works because I'm passing messenger in as the context to the each function and so within getMessage, this.getGreeting works because the this pointer is bound to the messenger object. And again, you'll find lots of different ways and lots of different reasons of why you'll want to use this. And I'll use this a number of different times at the example that I show you at the end of the course.
Map
The map function is used to iterate over an array and transform that array into another array. Here, let's Run the code for this first example and I can show you. So, when the code runs you can see that Craig, John, Dan, and Elijah are all mapped from an array. So, by calling map and passing in names, the iterator function is called for each item in the array. Notice the return statement. What's happening is that the map function is creating a new array from the values that are returned from the iterator. So if you need to transform an array into a different one, map is the way you want to do it. You could even do this more with a declarative, functional-style as well, by not using the anonymous function as the iterator. So, when you go over to Pass Function, you can see that I have the author's array and then I've created a function called greet. That returns Hello plus the name. And then when I call map I'm passing in authors and I'm passing in the iterator of greet. And so what's created out of that is an entirely new array of greetings. Then from there I can call each, passing in the greetings array, and telling it to log each one. So by using this type of style, it's very easy to read exactly what's going on within the code. I'm mapping the authors through the greet function and then I'm iterating each one of the new items in my greetings array to the log. Now, if you notice at the top you can see map and it also has an alias of collect. The each function had an alias of forEach. So here in the next example, I'll show you how to use that alias and how you'll get the identical results by using the alias. So let me Run this first and you can see that Craig spent $100 in California, John spent $200 in Florida, Dan spent the most in Arizona, and Elijah spent some money in Tennessee and I think this is for the gummy bear budget. But, I'll start off by having a data object, which has a nested array of people. Then, down a little further, you can see that an object is declared called OrderItem, that it takes in a person. So when getSummary is called, it returns this string here based off of the data that's passed into it. So then when you go down and call collect data.people is passed in as the data source or as the input for the function. And the iterator goes through and creates a new instance of the OrderItem object, passing in the value. So then, the result of the m variable is an array of OrderItem objects. Then from there, each one of those are iterated over using the each function and then calling getSummary and logging that out to the results pane. So, the value of map is to be able to take an existing array and create some sort of transformation or some sort of different result based off of that array. You may make some minor changes to existing data or you might do like what I did here and create entirely new objects or just print out simple strings. It's all up to you.
Reduce
The reduce function takes an array and produces a single result from that array. So here with this first code sample you'll see that I'm summing up all the values within my values array. I do that by calling reduce, passing in the values, and then setting up my iterator to decide what I'll be doing with those values. So here I'm doing sum, but you could do anything you want within the iterator. Let me Run this real quick. Now you'll notice that the signature for the iterator has memo and then the number. This function uses memoization so let me speak for a moment about what memoization is. The word memoization comes from the same root as memorandum. So, the idea being expressed here is the function is trying to remember something that has already happened, for instance the calculation of a value. When a function is memoized, the first execution runs like normal and the logic inside the function is run and it returns a result. This result is cached for subsequent calls to the function. The next time the function is run, with the same inputs, rather than executing the logic in the function again the cached result is returned. This technique is used to speed performance of a given set of logic or simply to remember previously calculated results, which is exactly what's happening right here with reduce. As you can see over in the results pane, the list items show what's being calculated as the function is run. So in the beginning, the first value that's placed into the memo argument by reduce is the first value within the array. So it says Calculating 100 + 200 and that returns 300. So then, 300 is placed into memo and so the next time it runs, memo plus the last value of 100 equals 400. So the memoization of reduce allows it to keep track of the last results, which is then passed back into the function. And in this case, it's the running total, which makes it easy to sum up the values within this array. Now, reduce doesn't always have to pass in the first value in the array as the initial value of memo and so this next example shows you how that works. Here I have an object with an array of people and so when I want to create the final value of total price, I use reduce by passing in data.people and then I have my iterator function, which again takes in memo and then value. The value in this case is an object in my array so I need to do value.price, but you'll notice that by passing in this context, the integer 0 here, memo starts at 0. I do this because I'm not working with just an integer array, but I'm working with an object array. So, I need to see it with a specific value so that the math works out correctly. So the 1st pass, 0 + 100 = 100 and then it goes on and on by keeping track of the last result. Now, you may want the results of reduce to be a little more sophisticated than just a single value. So here, I show how you can return an anonymous object. So here the data's the same, I've got my data object with the people array. I'm calling reduce by passing in data.people and the iterator is set up the same way as well, I've got memo and value. But, instead of just returning a single value, I'm returning an object that has a key of price and the value is memo.price + value.price. So, this keeps a running total of all the prices within my array. And then when I go to use it, I can use total.price to show the result. So there's quite a bit of flexibility of how you use reduce. Now I showed you how to do totals and summation of values, but again the concept is taking an array, boiling it down to a single value, and however you want to process that is completely up to you.
ReduceRight
Now reduceRight works just like reduce, except it begins processing the array from the end of the array instead of the beginning. So you can see the result here that's produced from the productIDs array, are the values that are found in the right-most part of the array if you were to string it together in a single line, all the way over to the values at the left-most side of the array. So reduceRight works exactly the same way as reduce except it just starts at the opposite direction. So here I create the productIDList by calling reduceRight and passing in the productIDs. The iterator here has a memo and the value and at this point, I'm just processing it a little bit differently in order to create a flattened list of this multidimensional array to give me a full product ID list. Now you can do the same type of thing with Objects as well. Here I have an array of products and I've just got the product IDs in here. I'm calling reduceRight by passing in the products and then inside the iterator I'm keeping a full list of the product IDs by concatenating on the latest product's ID by using val.id. Once I have the full list, then I can log that out to the results window as well.
Find
Now the find function allows you to find the first value based off of your criteria within your array. So, I've implemented this demo using a little more of a functional style, by giving certain criteria functions that I can pass in to find, in order to return the result that I'm looking for. So here I have my values, an integer array from 1 to 10 and then I've got evenCriteria where I take a look at the modulus and if that's equal to 0, then I know I have an even number, oddCriteria is the inverse of that. My greaterThanEightCriteria, which looks at the value and sees if it's greater than 8 and lessThanFiveCriteria does well, pretty much the same thing except it's looking to see if it's less than 5. So here, I can log whether or not I'm finding the first even number by calling find, passing in the values, and then passing in the evenCriteria. So in this case, evenCriteria up here, acts as the iterator for the find function that it's applying against the values, and the same thing for oddCriteria and the other two that I've set up. So, you could very easily have functions in some sort of common library that define data that you need to find within your array. But notice, that the find function only finds the first occurrence of the data that you're looking for based off of the criteria. There's another function that will find everything you're looking for, but find just finds the first instance of it. If we're working with an object array, things are much the same. So here I have my values, an array of people here, Craig, John, Dan, and Elijah and we have state and price. So evenCriteria, oddCriteria, greaterThanEight and Five, on and on. Notice how the value that's coming in is the instance of the object, not just the numerical value. So, I need to do value.price and then I can apply the same type of logic in these criteria functions as I did before. So again, I can take a look at the values. I can call find, pass in the values, pass in the evenCriteria. That will return a single object so then I can do .price in order to get the value that I'm looking for. So find is the function you want to use if you want to find the first occurrence of data given the criteria that you pass to it.
Filter
Now the filter function allows you to, surprisingly, filter out some values based off of criteria that you pass it. And I think you'll notice that some of these criteria look kind of familiar from the last demo that we did. So here I've got my values, which is an integer array of 1 to 10, even, odd, greaterThanEight, and lessThanFive criteria are all defined as functions. Then I can call filter, pass in the values, and give it the criteria that I'm looking for. So, what's interesting is that you can create, like I said, a library of these different criteria functions and use them in many different cases. So, here you can see I've filtered out all of the values that do not match my criteria, given what I'm looking for. So, I have a list of Even numbers, Odd numbers, Numbers greater than 8, and less than 5. That works great on an Integer Array. Now let's try it on an Object Array. So here I have my array of values and you can see I've got name, state, and price and I have basically the same type of criteria functions as I had in the last demo. The main difference here is that since I'm working with objects, I need to know which property of the object to look at in order to evaluate the criteria. So notice down in evenCriteria, you can see that I'm going to value.price rather than just the value that's coming into the function. Beyond that, everything else is the same. It's the same logic that I have in these functions as I did in the other one. So now when I go to call filter, I pass in the values and I can pass in my criteria functions and then at that point I get back the list of filtered items and then I can iterate through each one using the each function.
Where
Now, if the find function finds the first match based off the criteria that you send it, the where function will find all the matches based off the criteria you send into the function. So, with my data here you can see that I've got a number of different courses. I've got some by Dan Wahlin. A couple of them here are on different levels so I've one Intermediate, a Beginner, and another Beginner. I have some by Craig Shoemaker, John Papa, Elijah Manor. Notice, different authors in different levels are all within this object array. So, I'll run this and you can see that when I'm trying to find the Intermediate Courses, I call the where function and pass in the courses and then add in an object that has the key and the value that I need to match on the data that it's querying. So here it'll find all the courses where the level is equal to Intermediate. Now, I can get more specific than that as well. If I want to find all of Dan's Beginner Courses, that's just as easy as building up an object where I have the key of author and the value of Dan Wahlin, the key of level and the value of Beginner. Then when I pass that to where, I get back an array of matching objects that adhere to the criteria that I sent into the where function. Now sometimes it's easy to confuse find and where, so just remember that when you're looking for all of the matching items, you're looking for data that matches a where clause, like if you were doing it in SQL. So, hopefully that just gives you a little key to remember which function to use and when.
FindWhere
Now, a find locates for you the first occurrence of the data that matches your criteria and where takes in an object literal, describing the criteria instead of a function like find does. findWhere brings those two together. So, let's take a look at the data for a second. I've got that same list of courses and now what I want to do is find the Intermediate Courses and also Dan's Beginner Courses. So, instead of having to implement a criteria function I can just pass in the object. Again with the key and the value matching what you want to find, whether I have a single value, like if I'm looking for Intermediate or if I have something that's a little more verbose by looking at author and level, findWhere will find the first occurrence of whatever you're looking for and return it to you.
Reject
Reject is basically the opposite of filter. So, given a certain type of criteria, you're going to get the values back that are not within the criteria that you pass in. So I've got my integer values and I've got the same criteria functions that I've had in the past and when I call reject, you can see that when I pass in the evenCriteria, I get back numbers that are not even. When I pass in the oddCriteria, I get back the even numbers or the numbers that are not odd and on down the line. The criteria functions change just a little bit when you're working with objects. Again, instead of the raw value coming in, you need to take a look at the object and find the member that you're looking to evaluate, but the concept is the same. Reject will return the values that don't match the criteria that you pass in.
Every
The every function applies a truth test to all the values within your array. Now, before I dig in to the code, let's take a step back for a minute and look at how JavaScript deals with the truth. Now looking at this code, do you think that x == y will evaluate to true or false? Right, false, because y is a string. Even though it says true, it's still a string and not an integer. Okay, well what about this one? Is x equal to y? Well, JavaScript says yes. The double equal attempts to do a type coercion in order to determine whether or not the two values are equal. So, even though you have a Boolean value and an integer value, according to JavaScript using the double equals, they're equal. So, you need to be really careful when you use the double equals because you can get some unpredictable results. What about this one? Notice that there are now three equal signs used to evaluate. This returns false. When the triple equals is used, there's no type coercion involved and the values are simply evaluated as they stand. So, you'll hear the terms truthy and falsy and that just refers to JavaScript's way of determining truth or falsehood even when type coercion is involved. So, knowing how JavaScript will determine truth and false is important when you're using Underscore's functions that evaluate truth tests. Now what the every function does, it attempts to apply the truth test to every element in an array. So, here I'm looking at my values. I've got a Boolean in the first position, an integer, a null value, and then a string in the last position. So, when I go to Run this code, you can see that the very first one here, it looks to see are the values truthy? Well, for this first one here it returns false, because there's a null value within that array. So, since all of these items or every single one of these items doesn't have a value, then that's going to return false. What about using type coercion? Again, that's going to return false because I've got a string, I've got a null value. So, I'll get a false value there as well. And the same thing using the triple equal sign, but what happens if I change the date up just a little bit? Now in my array I've got no undefined or null values. So, if I first look to see if they're truthy well, that returns true because again, there's no null values in there. If I look to see if every single one of them are true using type coercion, that will return false because again, I've got an integer and a string and the same thing using the triple equal sign. But, if I change the date in the array to have true Boolean values all the way across the board, then you'll see that each one of the truth tests returned true because there's a value and it's true. When I take a look at an Integer Array, everything's got a value. So, when I'm evaluating for truthy that will return true. Next, if I look to see if they all are true, well only the first one is going to return true on that one. And then I'll also get a false value to see if it's an actual Boolean true value. Since those are integers, they'll all return false. Again though, if only one item within that array doesn't match the truth test, then every function will return false. Now let's take a look at it, of evaluating against text. Here, I want to look to see if all the records have a value for the state property. So, my truth test or my hasStateCriteria, just looks at the incoming object and returns whether or not state equals an empty string. And since the last one in the array does, the every function will return false because even one of them didn't pass the truth test.
Some
Where the every function looks at the incoming values to see if every single one of them passes the truth test, the some function looks at the values to see if any of them passed the truth test. So, similar to how we had it before, I'm using the same type of evaluation and the same data except I'm using the some function instead of the every function. So here, 'Are some values "truthy"?' Well, they all are because they each have a value. Are they truthy using type coercion? Yes they are as well, because although null will evaluate to false, all the other ones do so some of them are true. Are some of the values actually true? Yes, the first one in the array is. So let's change the data up a little bit and you can see that each one has a value, type coercion returns true, and the first one is actually true once again. And we get similar results by making the entire array filled with true values. Now, let's take a look at that integer array again. I want to know if some of the values are truthy. Well again, using this criteria they all are. I want to know if some of them are true using type coercion while the number one is. Are some of the values true? Well no, none of them are actually true, because they're all integers within the array. Then I can find out by passing in criteria if some of them meet the criteria. So, are some of them even? Yes, and are some of them odd? Yes. Now, if we take a look an Object Array, we can also find out if any of the records that we have in our array have a value for state. So, hasStateCriteria looks to see if state does not equal an empty string. And here, I'm using the any alias instead of some and asking if the values, if any of them, have the state criteria. And since most of them evaluate to true, the final result is true.
Contains
The contains function or include, looks to see if the array or the object contains a specific value. So here, I can look to see if the array contains a null value and it does within the third position. The number 1 is in the second position. The string of 'yes' is in the last position, but it doesn't contain any false Booleans. So, calling include, passing in values, and then passing in the false value will return false. So the way contains works is you pass it the values you want to look at and then the actual value that you want it to evaluate against. So, if we take a look at an object, you can see that here I have an object of author, firstName of Craig, lastName of Shoemaker. Here I want to see if the author contains the value of Craig and this does return true, because firstName is equal to Craig.
Invoke
The purpose of invoke is to call a method on each item within an array. So here, what I can do is invoke the sort method on each one of the arrays that are passed in to the invoke function. So when I run this, you can see that each one of the arrays are sorted because right here, when I call invoke I'm passing the method name of sort. So, as it goes through each one of those items, it runs that method and returns back the resulting values. Now, if you add Extra Parameters to the invoke statement, so notice here, I've got the same arrays, but now I'm calling join instead of sort, but I also have another parameter, which will be passed in to join as the pipe character. So now, when I run this, the arrays are flattened and delimited with the pipe. When I'm working with an Object Array, you can see that the getSummary method is being called on each one of the items in the array. So here, I have an object definition here where I'm passing in a person and I can get the summary. So I have an items array that's created and I push in a new item here for Craig, who lives in California and spent $100. Then I've got John who lives in Florida and he spent $200. So the results is a new array that's filled up with the result of invoking that method on each one of the items and getting the results. So each time it goes through an item within the items collection it calls getSummary. And the string that's returned from getSummary, which you can see up here, is the message that's printed out on the screen, is what's filled up in the results array. Once I have that, I can log the results. And notice that if you try to invoke a method that doesn't exist, you'll get a TypeError.
Pluck
The pluck function is used to extract out the values from an array, given a certain key or property name. So, you'll notice here I've got an array of authors and what I want to do is just get the author names. So when I Run this, I get John and Dan returned into the results array. Now you can also do this with some more complex-type of objects as well. So here, I've expanded the author's array so I have the name and state and also the courses that they've done. So John has a couple courses and Dan has a couple courses. So this time when I pluck out courses, it fills up an array with all of the array values that came from the original objects.
Max and Min
The max function calculates the maximum value in a collection. When evaluated against an array all you have to do is pass the array into the function in order to get the maximum value. When calculating max against an Object Array, you need to create an iterator function that returns an object property that you want used in the calculation of the max value. In this case, I'm returning author.budget all to find out who has the largest gummy bear budget. Just like the max function, the min function calculates the minimum value in a collection. When evaluated against an array, again you just pass in the array and it figures out the minimum value. When working with an Object Array, you just do the same thing with the iterator. Here I'm returning again author.budget and you can see that unfortunately, John has the smallest budget for buying gummy bears.
SortBy
The sortBy function again works with objects and arrays. When we take a look at the Integer Array here, at first this might seem kind of odd because array has a sort method on it. But, using the sortBy function allows you to take more control over how the sorting happens. For instance, when you take a look at the sort criteria you can see I'm evaluating whether or not I have even numbers or not. So here, I can sort the numbers in my array by even numbers first and then odd numbers. So using sortBy gives you a lot of control over how you manage your data. If I take a look at a String Array, again, if I just call sort on the array itself it'll sort it alphabetical. But maybe I want to sort the names by length of name and here I can do that very easy by implementing the correct iterator function. When I'm working with Objects, there are two options you have available to you. Notice down here sortBy, I'm passing in authors and I just have a string that says which property on the objects I want to sort by. So when I run this, it sorts it alphabetically by name. But at the same time, I can go over and implement an iterator so that I can do something perhaps a little more complex. So let's take a look at the data here for a moment. I have the author's array, which has author objects in here for John, Dan, Elijah, and Craig. Now, I also have another array that came from say some other source that has the SortOrder for this array. So, this is set up so that the SortOrder value matches the data and the authors based off of its index array. So if we come down to sortCriteria you can see that it's returning the value from authorSortOrder based off of the index that's being passed into it. So now, when I call sortBy I pass in the authors, pass in sortCriteria, and then the sorted authors are returned from that. Then at that point, I can just log out the series of sorted authors. And you'll see here that based off of the index values in authorSortOrder the data is being shown in exactly that order.
GroupBy
Now the groupBy function again gives you an opportunity to iterate over a collection and implement an iterator that determines how you will group the values. So here, I'm grouping the numbers by absolute value. So you can see that 1 and -1 and 1 all show up in the same group. What's interesting about how this works, let me go ahead and refresh this here and run it again, the groupBy function returns an object and the keys of that object are whatever you determined the group was within your iterator function. Whatever the criteria you used in order to group the items, is what ends up being a key within the object. So here, I did it by the absolute value of the numbers passed in so the key here is 1, 2, 3, 4, and so on. So, I'm jumping ahead a little bit to one of the other functions in Underscore that I'll teach you more about later and that's the keys function. So by using this function I'm able to extract out just the keys of that object and then I can use that to iterate over the groups. So here, now that I have just the keys in the object, I can iterate over each key and then call the logGroup function. That passes in the key and then I can go and take a look at the groupedValues and log the data that's associated with that property. So the key thing to remember here is that when you call groupBy, the returned value will be an object where the keys match the criteria you used to do the grouping. Now let's take a look at an Object Array. So here I have on array of authors and then when I call groupBy and pass in the authors, here I'm just saying that I want to group by the state. So this is just a string, which represents a property within the objects. So when I Run this, I don't need to have an iterator function set up in order to take a look at that property name. I can do it just by passing in the string. So again, once I have the groupedAuthors then I extract out the keys, iterate through each one of the keys, and then I can call logGroup. Here, as I iterate over each group I have to implement an iterator for the each function because I'm looking at an object, because what I want to do is log value.name. So that's how you do it by passing in the string value of the property that you want to group against. You can also do the same thing against an object array using a groupCriteria. So here what I'm doing is I'm grouping all of the authors by whether or not they're in a coastal state or a landlocked state. Again, I get the groupedAuthors by taking a look at authors and passing in the groupCriteria. The groupCriteria will look at each one of the values that comes in and determines whether or not the state is either coastal or landlocked and here I'm just keeping the list small, it's California and Florida. Everything else is landlocked. Once I have those groupedAuthors, again extracting the keys, and then I can iterate through each key and then log the group. Using just these few Underscore functions makes it very simple to do groupings of data within JavaScript.
CountBy
The countBy function works in a very similar way to the groupBy function. If I take a look at the Integer Array, you see I have the same array of values. I also have the same groupBy criteria. So, I'm grouping by absolute value of the numbers, but this time instead of getting back the values in groups, I'm getting back the counts in groups. So you can see that there's 3 values in the group named 1, 1 in 2, 2 in 3, and so on. It operates the same way as groupBy does in that the result of countBy is an object where the keys are whatever you created within the groupCriteria. So I can use the same approach to extract the keys, iterate over those keys, and use that to reach in to the countedValues in order to extract out exactly what the counts are for each group. Also like groupBy, I can do the same thing with property name of an object. So here I have my list of authors and I want to count how many live in different states. So when I call countBy, I can pass in authors and then pass in the string for state. Once I have the countedAuthors then I can extract out the keys, iterate over the keys, and at that point, I know how to handle the groups. So here I've got some logic that kind of deals with the pluralization when there's more than one author in a state and then I can just log the value, which comes out of countedAuthors, by passing in the key. And remember this is the same things as doing countedAuthors.fl for Florida, in the case of the first item in the array. And then I create up the rest of the message and print it out on the page. You can also do it with the groupBy criteria. So here I can get the count of authors that live in coastal or landlocked states. I've got the same array of authors and the countedAuthors is generated by calling countBy, passing in the authors, and then the groupBy criteria. Again, it just returns the object that has the keys that match whatever criteria you're using in order to do the groupings.
Shuffle
When you take a look at the Underscore documentation, it says that the shuffle function uses the Fisher-Yates Shuffle Algorithm. The Fisher-Yates Shuffle Algorithm, also known as Knuth shuffle, is an algorithm that is used to create a randomized set of values without repetition. Consider for a moment that you have 10 songs on your iPod that you want shuffled. Now with a truly random shuffle, the last song you just heard could just as easily be the next song on the list, unless you have some way of marking that song as being ineligible for being an option as the next item in the shuffle sequence. What you really want is a way to say that, as soon as that song is being played, it's no longer in the set of possible values, even when the next value is being determined randomly. The Fisher-Yates Shuffle does exactly this. As each item in the shuffle is determined, it's no longer an option or is marked off the list for being picked in the next random selection of values. And you get all this functionality very simply by using the Underscore shuffle function. Now back to the demos. When working with an Integer Array, all you have to do is pass it to the shuffle function and so each time I Run this I'll get a different shuffle of those same values. And you'll notice there's no repetition going on in any of the series. The string array is the same thing. All I have to do is keep hitting shuffle and I get a different order each time, no repetition. Now what happens if I have a Mixed Array? Well, actually, it works on that just as well. Perhaps a multidimensional array? Now, the way that my log function works, it's taking a look at the nested arrays and putting them in individual list items, but what's being returned from shuffle is a shuffled list as another multidimensional array. So, shuffle isn't transforming the data as it's coming through, but my log function flattens it all out. What about an Object Array? Same thing here, each one of the items is being shuffled all along the way.
ToArray
As the Underscore documentation states, the toArray function is often used to convert the arguments of a function into a real array. Did you know that the arguments of a function are NOT a real array? Well in fact, they are not. The arguments of a function aren't a real array because the arguments does not have any of the same properties of an array, except for length. So often, you'll find that you might want to use toArray for arguments and for other purposes as well. Here I'm creating a sum function and I'm not explicitly stating anything in the function's arguments because I'm just going to grab the arguments as they come in. You can see down below within the usage, the number of arguments can grow or shrink, depending on whatever's necessary. So, the first thing that I'll do here is call toArray against the arguments, which converts the function arguments into a regular array. Then I can do some interesting things like call reduce in order to sum up all the values within that array. So here, I can call sum, 2, and 2 or 5, 2, and 8 or even this longer series of numbers in order to get the actual value that's summed up from the argument list that's passed into the function. What about another way of using it? What about Strings? You can pass a string into toArray and you get an array of characters from that string. So you notice, once I have the values, I can say that strings are made up of individual characters. And I can grab the first item from that array by passing in index 0, which returns 1 or it can iterate through the entire array to see how they're split across. So the string 1, 2, 3, 4 creates an array with 4 positions in it with the values of 1, 2, 3, 4. What about using it on an Object? Well, if I run this you can see that it extracts out the values from the object. Like the comment says here, there's a better way to do this and when I get into the object functions you'll kind of see that in action. But, I wanted you to see this so you could know how the 2 array function operates when you pass in an object to it.
Size
The size function works very similar to what you'd expect from the length property of an array, except this will work on objects and arrays. So when I have the array of values and I Run the size function against it, you can see because there's 4 entries in the values array. If I Run it against an object, you can see that I get 2 because there are 2 properties in the person object. And an Object Array really is no different from any other type of array, but here I wanted to show you how this would behave as well. Again, returning the size of 2, because there are 2 objects within the people array.
Summary
Underscore includes a myriad of different functions that make working with collections of data much, much easier than trying to accomplish the same, old things in plain, old JavaScript. Now join me for the next module, which covers Underscore's family of functions, tailor-made for JavaScript arrays.
Arrays
Introduction, First,Iinitial, Last and Rest
Underscore functions crafted to work with Arrays give you an opportunity to extract items, find overlapping data, find specialized indices, and much more. Alright, let's begin with the first function. The first function returns the first element in an array. And if you pass in an Explicit Amount as an argument, it'll take the first number of items based off of the number you pass in. So, take(authors, 2) returns the first two items within the array. Just like first, the initial function returns everything except for the last item in the array. Now, if you want that change that up a little bit and pass in a value for the last argument, it will take everything except for the last number amount that you pass in. Following the same pattern as first and initial, last will return to you the last item in an array. Now, if you pass in a value as the last argument to the function, it'll return to you the last end number of items in the array. Finally, the last function in this kind of "group" of functions is rest and rest will give you everything except the first element in the array. Of course, unless you pass in a specific index, which indicates which index to start at in order to give you the rest of the elements in the array.
Compact
The compact function takes an array and removes all falsy values from it. Well, that's what the documentation says, but there's something that I want you to be aware of. Watch when I run this. You'll notice that I have Craig, the number 1, the text One, then the value of false and an object. Let me run it one more time and stop at the break point. So, when we take a look at the values after compact has been run, you'll notice that this array here still has a false value in it. So, make sure that when you run compact, you're only expecting the falsy values to be removed from the first level of the array. In other words, if you want it to work for multidimensional arrays, you'll have to recursively go through those arrays in order to strip out the values.
Flatten
The flatten function will take an array, whether it's a nested or a multidimensional array, and flatten it down into a single, flat array. So, you can see here I've got some data here about a specific author so these are topics that I've done on Pluralsight and some contact information. So, when I call flatten, all of that will be returned into a single array and you'll notice here that the flatten array length is 27 items. Just so you can see for yourself, let's take a look at it in the debugger. Here the author array is a multidimensional array with some extra values in position 0 and 1. And the flattened version is just a single array with all of those values. Now, the flatten function will work no matter what depth or how many levels down your array is. But, what if you wanted to only work on the first level of the array? If you pass in a Boolean value as the second parameter for flatten, that tells it to only do a shallow flattening of the array. So, when I Run this you can now see that the shallow array length is 11 and here's all the different values that are in that array. Again, let's take a look at it in the debugger so you can see what it looks like. Here's the original array that has 2 arrays in the 2 and 3 positions of the array, but then it has arrays even further down. So, this array, this array, and this array all will not be flattened, but the array at position 2 and position 3 will be flattened. So now when we take a look at the shallow result, you can see that the course names that were at the bottom level of the first nested array, now are flattened down into the root array and the arrays that were further nested in the array are now brought down to the root level as well. So, depending on how you want to look at the data in your array you may want to call shallow or just allow it to flatten the entire thing.
Without, Union, Intersection and Difference
The without function returns a copy of an array without values that you specify to it. So when I Run this you see that the resulting array only has Craig Shoemaker because I called without, passed in author, and said that I didn't want any of the active or 1 values in the resulting array. The union function will take in two arrays and return only the unique values between the two arrays. So, notice in the speakers array, Dan Wahlin and Craig Shoemaker appear both there and in the authors array. But when I Run this, I get a single list of only unique values between the two arrays. Intersection will look at two arrays and return a unique list of the values that show up in both arrays. So notice that Scott Guthrie is just speaking at the event and Craig Shoemaker is only an author and so when I Run this the overlapping values, John, Dan, and Elijah are the ones that show up in the resulting array. Difference takes a look at two arrays and also returns a list of unique values, but it's going to look at the first array and compare it with the second array. So, when I Run this you'll see that the values of Scott Guthrie and Martin Fowler are returned as the result, because that's the difference between the values that are in speakers and authors. But notice in authors, Craig Shoemaker shows up in authors and not in speakers. Difference returns the values that are in the first array or speakers that are not in the second array. So, you'll want to make sure you have that distinction in your mind, that it doesn't return only unique values from the two arrays. The uniq function takes a look at the incoming array and produces a result that has only unique values. So notice in this array, the number 1 and 5 show up more than once. So when I Run it and get the results, I have the values in basically the same order, just only skipping any duplicates. It works on Strings as well. Here, I have Dan and Elijah being duplicated within the array. When I call uniq on authors I get only the unique set of names in that array. Now, one of the options you have available to you is to tell uniq whether or not your data is sorted or unsorted. So, let's take a look at running this and see how fast it is in order to iterate over a set of 1,000 first names. So when I Run this you can see that unsorted it takes 4 ms. That was 1,000 names in the array. There are 33 Unique Names and here are all the Unique Names. So that took 4 ms. What if we sort it ahead of time? Here, I'm taking the firstNames, sorting them, and then when I call unique I pass in values and then pass in the true argument to say that this is already presorted. So now when I Run this, against the same amount of values, you can see that it only took 2 ms out of the same set of data. So, if you can sort your data ahead of time or you know it's already sorted, you can speed up that algorithm by quite a bit. Now, what if you want to do something that's a little more involved than just a simple compare? Here's an array of product information. Notice how this is structured, the product id, the first one and the second is same except for the color code that shows up at the end of the id. The title shows that it's the same product, but the color shows that it's just a different color of that same product. So for Widget A and Widget B, it shows up in two different colors. Well here I can implement an iterator, which is the uniqueCriteria. So as a product comes in, I can take a look at the id and split it based off of the dash delimiter. Then from there, I can return just that first part of the id. So, it'd be this part right here. Now, if for some reason that id didn't have a dash or didn't work I'm going to fall back to using the product title, but for the most part I know that will work. So now when I go to call unique I can pass in the products. I know it's not sorted right now so I'm going to go ahead and pass in false and then pass in the uniqueCriteria. And when I do that, you can see that the initial length of products was 4. The length of the custom unique's products array is 2 and there's the Unique Names that are returned. And Widget A and Widget B are the Unique Names that are returned.
Zip
Zip accepts an arbitrary number of arrays and combines all the values into the single resulting array. So, when I Run this, you can see that the single array has all the data from the three arrays in it. But, let's also take a look at it in the debugger to see exactly how that works. So I'm passing authors, states, and courses, which are all flat arrays into zip. The values that are returned is a multidimensional array where all the values that are in the 0 index position of the incoming arrays show up in an array in the 0 index position of the final result. And all the values that show up in the 1 index position of the array, show up in the 1 index position of the results. So now let's take a look and see how it behaves with Nested Arrays. So here in have basically the same data, authors, and states except courses now is a nested array to show course names for each one of the authors. When I Run it, again I get all the information, but notice how it's organized. Since these topic names and this state name all associate with Craig, being in the first index position of those arrays, they're all associated together. Let's take a look at it in the debugger. So see, courses this time is a nested array and now when allValues comes through, index position of 0 will be Craig's information and it brings in that array from courses. So, as long as the index positions line up among data that you're getting from different sources, zip can be very useful to associate that data together.
Object
Object takes arrays and creates an object out of it. So notice here, how I have an array for keys and values. And these will match up to the keys and values that will be in the resulting object. So, when I call object by passing in those keys and values, I get back an object where I can call author.firstName, author.state, and even author.lastName. So this is a real straightforward way to go about it. If your data comes in a little bit of a different form you can use a Nested Array in order to pass in the keys and values. So notice I have the data array and each element in the array is a key and value pair. So if I have data set up like this, I can pass it to the object function all together and I get the same object as I did before.
IndexOf, LastIndexOf and SortedIndexOf
indexOf will return the index of an item based off of the value that you provide. Now, if there's a native index of implementation available in the environment then it will defer to that. So when I look at an integer array, I can see that index 5 is at index 1 position. It can work against a String Array. Index of Elijah is 2. Now, you can also provide a start location. You can tell it where you want to begin looking. So, if I pass in authors, tell it to look for the index of Elijah, and then give it the index 3 to Run, it'll start in the index position of 3 and then return the result from the next occurrence found. So here, since I'm starting at index 3, the index of Elijah now is 4 instead of 2. If it can't find an item in the array, the index will return -1. And you can also do a Binary Search. If you know that your data is sorted it will use a faster algorithm. Now, I'm using Chrome and it has a native implementation of indexOf so this is going to go pretty quick either way. But notice, I'm bringing in the firstNames array and again, that's a list of 1,000 first names, but when I get the unique names it comes down to about 33. Then I take that list and shuffle it. So you can see the first instance, when I'm calling indexOf and passing in the shuffled list in the second instance I'm passing in a sorted list and telling indexOf that the data is presorted. If I continue to Run this, you can see that the index of Steven changes at the top, because that's the shuffled list and it remains the same for the second one because that's the sorted list. Down in the console you can see that either way it's performing pretty fast. lastIndexOf returns the last index position where a value occurs in an array. Now notice, up at the top there's the E5 icon so this falls back to native implementations when it's available. In the first example, I'm looking for the lastIndexOf 5 and since it shows up twice, I'll get the returning value of 8 because it shows up in the eighth position for the last time. When we take a look of how it works out with Strings, here Elijah shows up twice, but when I ask for the lastIndexOf you can see that here in position 4 of the array, is the value that it returns. Now just like indexOf you can provide a start location for lastIndexOf. So, when I ask for the lastIndexOf Elijah, but say start at position 3 in the array, the value is now 2. And of course if it can't find anything in the array, the return value is -1. sortedIndex returns to you the index of an item if you were to insert it into a sorted list. So the input needs to be already sorted as sortedIndex uses the binary search algorithm in order to find the final value. So, if you take a look at my Integer Array here, I have a scrambled array and it even has some repetition in it and I did that on purpose. So the first thing I'm doing is sorting the array and then when I come down to sortedIndex I pass in the values and ask what the index for the integer number 7 would be if I were to insert it in this sorted array. Now, when I Run it you can see that it lists out all the values with the associated index values that it has in the array and you can see that in order to insert the number 7, I would want to put it at position 8 and that's exactly the right spot. Let's take a look and see how it behaves with strings. Here again, I've got an array of names and I also put some repetition here on purpose. So when I call sortedIndex against authors and ask where do I need to insert Elijah, you can see that the index position is 3, even though I already have 2 entries for Elijah. So, as long as I'm sorting my data before I'm passing it into sortedIndex, I'll get the appropriate index value to insert it into if I were to add that item to the index. Now, you can use this on objects too, not just arrays. This one takes an iterator though. So here, I have my array of authors and I also have a new object that I'm creating, just for Julie. So maybe I have an existing data source and now I have a new object that I want to add in to that collection. But, I want to make sure I added it into the right position. My sorting iterator takes a look at the incoming author and returns the name property so that as the function begins to sort it's looking at the same data for each one of the objects. So now when I call sortedIndex I pass in the authors, I pass in the julie object, that has the same property as all of the other objects so it will be looking at .name for the data source, as well as the julie object. And when I Run it you can see that the index to insert Julie is at position 4, which is exactly right.
Range
Range generates a list of numerical values and you have some flexibility on the results based off the arguments that you pass in. So, if you pass a stop value only then it will begin the range at 0 and it continues to the stop value. But notice that the stop value is not inclusive in the range. So the values here go from 0 to 5. You can also provide a Start Value, along with stop and it begins the range at the number provided. Here, there are 8 values generated going from -2 to 5 and again notice that it stops before the given stop value. Finally, you can also provide a Step value. And here the list goes from -2 to a stop value of 6 in increments by 2, but since it's not including 6, there's only 4 values as a result.
Summary
Now, Underscore really shines in working with arrays and collections. In this module you've seen how the family of array-based functions can help greatly simplify working with JavaScript arrays. Now, join me for the next module, where I cover how Underscore can help you control and compose functions with very little effort.
Functions
Introduction
The series of Underscore Functions that are crafted to work specifically with your functions can greatly help you gain control of how your code is executed, manage where data is coming from, and help guard against some of the odd behavior found in native JavaScript. The bind and bindAll functions help you manage the JavaScript this pointer, wrap and compose give you some handy utilities for making functions work together, and all the others in-between help performance or help you gain precise control on how functions are called.
Bind and BindAll
Bind helps you manage the reference of the this pointer in functions that you write. Before I start with the code samples, first I want to refresh your memory a bit about how the this pointer behaves by default in JavaScript. Ah yes, the JavaScript this pointer. If you've ever spent some time in formal object-oriented languages, encountering how JavaScript handles the this pointer can be a little bit confusing. Now, I'll review just some of the basics for you, but for an in-depth discussion on the subject, one resource you may want to check out is this page on the Mozilla Developer Network. The URL is a little bit long so you can even just search out JavaScript's this pointer and you'll get a lot of good information. By default, JavaScript operates under a global context. So, if you create a function and call it without attaching it to any other object, then the this pointer refers to the window object. Now, if you take that same function and call it from the click handler of a DOM element and then call it by clicking on the element, the this pointer no longer points to window, but rather to the element that it's attached to. Now, when you have a method on an object you would expect that the this pointer would route to the object since it owns that method, but in fact, it routes up to the caller instead when it's called like this code listing demonstrates. Now when you add binding into the mix, you can sidestep all that complexity and be deterministic about where the this pointer is referencing. Now I updated the code listing to include the bindAll function and I'll cover that in detail in the next clip, but the concept here is what's most important. By binding all the methods in the view model object, now even if the sayHi method is attached to the click handler of the button, the this pointer refers back to the containing object. So, binding helps you manage where the this pointer is referencing and there's a few different nuances on how it works, which I'll show you in the demos. Okay, with that background you can see that I've got an object here that has a name and a URL. I also have a function that's not a part of that object, but if you notice in the body of the function I'm using this.url and this.name in order to return the string for the anchor. In order to get this to work correctly, I need to call bind and pass in getAnchor and then pass in the person as the context of bind. Now, when I call getAnchor it returns exactly the text that I was looking for. So here's the anchor tag with the href of craigshoemaker.net and my name of Craig. So that's the default way of working with bind, but you can also pass in optional arguments. So here I have the same data object and the same getAnchor function except I've added an argument to it. This will help determine whether or not this link opens up in a new tag. So, any arguments that are added past the context argument are forwarded on to the function that it's calling. So here I can call person.getAnchor and since when I bounded I passed in the true argument, I don't need to pass it in when I call getAnchor. So here, this creates an anchor tag and you can see that it set up the target equals blank because the parameter that I passed into it during the binding was true. While bind creates a binding between and object and a single function, bindAll creates bindings for all functions or methods if you like, in an object. First, let's refresh on how this operates without binding. We're going to open up the debugger and when I Run this you can see that the first time that listNames is called, the this pointer points to the object of the view model. So, it has access to the authors array and that's because it's running right up here in an unattached context. When it's run again, now the way this code works is the first thing that I do is add a button up at the top and then down here at the bottom, I associate the function off of my view model to the button click. So now, I can click on this button and you can see that the this pointer is now pointing to my button. In fact, we can see the ID right here. So, I need binding in order to make sure that when this.authors is called, it's pointing to the view model and not to the controlling object. So let me uncomment the call to bindAll and refresh the page. So now bindAll is being run so I can Run this and here's the unattached instance of listNames of being run and that works just fine and now when I click on List Authors, it behaves the same way. And that's all because all of the functions within my object are being bound to itself. You may not want to bind every single method in your object to the object, so I'll Run the code in order to create the buttons so you can see that when logName is run this.name will point to the view model. When logButtonId is run, that's not being bound to the object so it will return the ID of the button itself. So, the name button has the ID of name-button and the idButton has the ID of id-button. So when I call bindAll, here I'm adding in an extra parameter saying the only one that I want bound is logName and this works as a parameter array so you can add as many method names as you want and only the ones listed in the function are the ones that will be bound to your object. So now when I click on Show Name, this.name is pointing to Craig Shoemaker and when I click Show ID, this.id is pointing back to the button that called that function.
Partial
Partial is a function that can help you prepare functions for future use. And one of the things that the documentation points out is that it doesn't affect the reference of the this pointer. When you use partial you can fill some arguments of a function ahead of time and use that function at a later time, even while defining extra arguments when you call the function. Let me show you here. This is largely the same code I used in the bindAll demo. Except now I'm creating a function called reportAuthors. In the listNames function I'm passing in a message and then I also have another parameter that decides whether or not I'll show that message. The key here is to show that the function is looking at this.authors in order to iterate over the array of author names that I defined in the view model. Now, when I create reportAuthors, I'm creating this as a partial. The partial is set up by pointing to the listNames function and then I'm passing in a value for the first argument of message and that is, 'is a Pluralsight author.' So, as I Run this, the unattached version of it shows the message because I passed in true for the second argument. It looks like it's the first argument when I call reportAuthors, but that's because partial is doing the work of passing in the value for the first argument. Now, even though I've bound it to this button for List Authors, now when I click on it it shows the names, but it doesn't show the message because, as I bind it to the click handler showMessage comes through as false. So, basically this just gives you a way to compose some of your functions in such a way that you're adding some of the information in ahead of time and you can pass those functions around and use them as needed.
Memoize
Just as I said on the slides, memoizing a function helps increase the performance by not requiring the reevaluation of logic of a function given the same inputs. In this example, I'm looping over the showNumberMemozied function 10 times, twice in a row. Here, take a look at what happens. The first run evaluates the implementation in showNumber for each iteration in the loop. And you can tell that because the log, inside of showNumber, is saying this function is run for and then it gives the index value. If we take a look at the second run, this path simply returns the value as produced by showNumber. So notice the loops, there's nothing different. I'm calling showNumberMemozied in both instances. So, this can greatly increase the speed of your code and it's all done just by calling memoize and passing in your function. Then from there, you just use the new function variable anytime you want to call that function. Okay, now let's take a look at what this might do in a little more of a real-world-type of context. So here, I have the algorithm for generating a Fibonacii value. Let's open up the developer console and what we'll do is take a look and see how long it takes to run getFibonacciValue, all the way up to 30 and we'll run it twice. So here, the first run took 52 ms and the second run took 25 ms. So, that's all done without memoization. Now let's try it with memoization. So here, this is the exact same algorithm used without memoization, but now I'm calling memoize and passing in the function name. The target is still 30 and now I'll Run this again. So you can see now, once it's memoized, the first call took 22 ms. Subsequent calls to getFibonacciValueMemoized took 0 ms. And here I can continue to press on this button to Run Again, and I'll get the same result and you can see, it might take a millisecond, it might take 0 ms, but it's still much faster than what it was without memoization.
Delay, Defer and Throttle
Delay is a function that works much like the native setTimeout function, but with a little bit more flexibility. In this example once I click on the button, after a second-and-a-half, some text is rendered to the output window. A second-and-a-half after that, the shout function is called to change the text just a little bit. The key thing to remember here is that if you pass extra arguments to delay, after the function to run, and the seconds to wait, they're forwarded to the target function. So, in this case, it's sizeinEms, which is 2 and the color, which is maroon. Defer defers execution of the target function until the current call stack is cleared. Here I'm logging a message to the output window and then immediately logging another message, but this time using the defer function. Then I call getFibonacciValue, which takes a bit of computational time. Notice the order in which the results show up. First, it's the 'I am an immediate message.', then the results of the Fibonacci calculation, and finally the deferred message. So, this function can come in handy when you need to update the UI after some intense calculations or perhaps building up some markup for the page. Have you ever needed to disable a button for a time, so that users wouldn't click on it a million times? Have you ever had to put checking code in a function to make sure that consecutive calls in a short amount of time skip some of your logic? Well, if you have then throttle is just what you need. In this example the log function is throttled so that it's called one and only one time during the given 100 ms. After that time has elapsed, then it's eligible to be called again. Here, let me show you. So, when I clicked on the button it went through the loop and iterated 1,000 times. But, as you can see my throttledLog was only called once in the loop each time testThrottle was called. So, you can configure the wait time, the second parameter in the function, to be whatever you need, but this will help you control how often logic is processed within your functions.
Debounce
Debounce is a function that you can use to make sure that your function is only fired after a certain amount of time has elapsed. The best way to explain this to you is just to show you. So, first what I'll do is Run the code here and what this does is this binds logDimensions to window.resize. Now, let's exit out of full screen and you'll notice, you'll see some information coming in on the results window. Now as I resize the window, every time the window moves, even just a little bit, it starts to log that information. If we take a look at the log you can see it's growing quite large. So that's just a raw attachment of my logDimensions function to window.resize. But, if I do it with debouncing, now I ran that code and it attached it there. So notice here, I'm calling debounce, calling logDimensions, and I'm saying every 250 ms is when this function can be run. So now let's do this once again and as I resize the window, kind of going along, and there, it's not a huge stream of information coming in. It's only running if it's been after 250 ms. And again, the way that's set up is I have my regular function, just like normal, but I'm passing it in to debounce and now when I want to call window.resize, instead of pointing to logDimensions I'm pointing to logDimensionsDebounced. Anybody up for some basketball?
Once and After
Well, once is pretty self-explanatory. So, here I'm wrapping a call to my log function in once and then I'm calling callOnce 1,000 times, but you'll notice when I Run this, it's only called once in the loop. So this can be really useful if you have a number of different asynchronous processes going on and you need to call some function, but you know you only need to call it once. So, whether it's from promises or callbacks or whatever you have going on, you'll probably end up finding a lot of use for this function in your pages. Now similar to once, after creates a wrapper around a function so that it will only execute after it's been called x number of times. So for instance, if I Run this, there are two buttons put up on the screen. And the way I have after set up is that depending on how many buttons there are on the screen, so I'm passing in the size of my confirmationButtons, which is two, then it can run the logConfirmation function. I'm taking the result of after and setting that into the click handler of my confirmationButtons. So when I click on Button One and then Button Two, only after I've run the confirm function twice does my result show up in the results pane. So again, there's a lot of use for something like this when you're dealing with asynchronous operations because when you don't know when responses will come in, but perhaps you know there's a certain set or a certain amount that you need in order to take the next step, this can come in really handy.
Wrap
The wrap function allows you to wrap one function inside another function. And it does this by passing the first function, sent to wrap, as the first argument to the second function. So, let's take a look at this code here. First, I'm calling wrap and I'm passing in foo and then bar. So, I'll Run it to get the result. Now when bar is executed, the foo function is sent in to the first argument. So it's represented by func right here. So, when bar is called, immediately foo is called. And you can see that by it printing up foo into the result window. Then bar has some implementation and so right here it's just logging bar and then the arguments that I passed to the wrapped function are delegated over to the target function, which is bar. So, that's why argument 1 and argument 2 show up inside of bar when I've passed them here from the wrapped function. Now this isn't quite a bit different, but you'll see the different style so I wanted to show you. You can also do it with an Anonymous Function and so this is basically the same implementation except one's using the Anonymous Function and the other one was just using a named function. But even when you see it like this, just know that the arguments that are passed in to wrapped are forwarded on to the target function, which is the second parameter in the wrap function. Now, one of the things that's not quite clear from the Underscore documentation is the fact that you can wrap objects also, not just functions. So first let's take a look and see what we have here. I have a settings object that has enabled logging and warning. Then I have the notify function. Now, I've wrapped settings so that the settings are passed in to this anonymous function. So when I call it, all I'll do is send in a message. And then based off the settings, it'll decide whether or not to do a console.log or console.warn. And then either way it'll log the message to the output window. So then down at the bottom I can call notify and pass in a message, 'Inventory critically low!' and I'll Run it. Now when we take a look at the console, you can see that the console.log and the console.warn ran, because the settings were being passed into it. So now, just to be thorough, let's go ahead and take a look at how you use it with arrays. And so, it's the same concept. Here's my values array and I'm wrapping it with the wrap function to the target for logLength. Now, I didn't declare any other arguments, but again if I did have them in this function, I could pass them in through the wrapped function. So when we Run it, you can see that the array's length is 10.
Compose
The compose function takes a list of functions and each function consumes the return value of the function that follows. Let me scroll down here and give you an idea of what that means. So the first function that will be run is funcThree. The result of funcThree will be passed in as a parameter to funcTwo. Then funcTwo will run. The result of funcTwo will be passed in as a parameter to funcOne. Finally, funcOne will finish executing and it will return a value. To see this all working, let's open up the debugger. So, to make the call I'm calling composition and passing in argument 1 and argument 2. The last function that's in the chain passed to compose, is the one that will receive the arguments that are given to the function that's the result of calling of compose. So, argument 1 and argument 2 will only be passed to funcThree. So, when I Run this you can see that here's funcThree and the arguments that are passed in are argument 1 and argument 2. So, it'll step through and do its thing. So now that funcThree is done executing, it will run funcTwo. So here we are at funcTwo and you can see that the previous value is that funcThree is complete because funcThree returned the message of funcThree is complete. FuncTwo will continue to execute and when it's done, it will return funcTwo is complete. So now it makes its way up to funcOne. The previous value here in the arguments is funcTwo is complete and it executes and finally returns a value. So you can see, up in the output window how the composition is happening. funcThree is run, it's able to process the arguments, it returns its value to funcTwo, and you can see right here that funcThree is complete, it's printed up because it was available in the arguments. The same thing for funcOne, having the return value from funcTwo in its arguments list. And here, I'm able to take the final result and log it out to the output window. So this could be very powerful in giving you the ability to compose together a number of different functions that perhaps do math calculations, manipulate the DOM or anything where the return value of one function could be used for the next function in the composition.
Summary
In this module you've seen how you can take control of functions that you write, improve performance, and make functions that wrap and build upon themselves. Now join me in the next module where I show you all that Underscore has to offer in working with JavaScript objects.
Chaining and Objects
Introduction
Underscore shines in helping you manage, create, and manipulate Objects. This module delves into the series of functions built to work specifically with JavaScript Objects. Now, since everything in JavaScript is an object of some sort, you can see from the second column that there are a number of functions that help you determine one object from another. But, before we deal with the object functions, there are a few features of Underscore that I've left until now to discuss.
Using the Object Oriented Approach
Now, I touched on this a little bit during the slides of the introduction, but there's a feature of Underscore that allows you to call functions either in a functional style or using more of an object-oriented style. Here I'm calling the each function, which I'm sure you're very familiar with by now, against the authors array. And so, by placing authors in the parentheses, I can simply call .each, pass in an iterator and a context. So running this code gives me the exact same output that I would have from just using the traditional approach of underscore, dot, function name, and then passing in the object or array that the function works with. So basically what's happening is that the input data is being passed in as the first argument to the function that you're calling. So, any other arguments that you would pass in to that function just come directly after calling the function. Now let's take a look at a different example and it's exactly the same for any function that you would call within Underscore. But here I have my array of author names and if I want to extract out the first name or if I want to extract out the last name in the list, I can do that just by calling underscore, parenthesis, the input, close parenthesis, and whatever function I'm calling. So again, it works the same way for any function that you'd find in Underscore.
Chain and Tap
The next bit of syntactic sugar is chain. What chain allows you to do is chain together a number of different functions in Underscore to finally end up with the resulting value. So here I've an array of product records and what I want to try and do is find the highest price of the item and I can accomplish that by chaining together a number of different Underscore functions. So, in order to find the most expensive what I'll do is set up the chain by calling _.chain and pass in the input data. The input for the functions that I'll be calling will be the output of the last item in the chain. So sortBy will get the raw products array. Once sortBy is executed, whatever the result of that is passed in to the last function. Whatever the result of the last function is, is what value will return. So anytime you're chaining together functions, you can chain as many as you want, whatever works for your operation, but when you want to stop the chain and get the final value, you need to call .value. So here, to get most expensive I begin the chain, I sort by price. Now since the sort is ascending I know that the highest price will be at the bottom of the list. So I can call .last and then call .value in order to get the final value. So the most expensive item on the list is $6.41 and with a quick scan through the numbers you can see that's in fact the case. What about trying to set up an average? Here I have another set of products and I'd like to get the average price. So here's a function that I have. I'll pass in the products, then I'll start the chain off by setting up with the products array. Now since this is an object array, I'll pluck out the price value. From there, I can call reduce. This basically does a summing operation. You've seen this a couple of times during the course. So, it sums up all the values that are found in the objects off of the price property. From there I can get the resulting value and then in order to find the average take the result and divide it by the number of products that I have. Then I'm just returning the result by calling toFixed at 2 decimal places in order to round up to the cents amount. Now, you can get as involved as you need to with your chains. So for this example, I'm supposing that I have data coming in from some sort of service and there's a set pattern to the data, but it's not exactly what I need in order to fulfill the requirements that I have for the application. So let's say for a moment that really, what I need at the end, is a list of the cars that come in from the data, but I only want to look at the cars that are not on sale. I need that list sorted by price, in a descending fashion, but I only want to look at unique car names. So, although Charger shows up twice and Mustang shows up a couple times, I only want to know about one occurrence of that. So completely unique values. So, let's scroll down and take a look at the code. In order to get those results first I'll need to filter, because I want to take out all the items that are on sale. Then I'll sort them by the dollar amount. Then I'll extract all of that data out of the object array into a simple array, then I'll get all those unique values, and then return the final value. So when we take a look at the result, you can see that Mustang, Charger, Eclipse, Camaro, and Sienna. So the most expensive car in the list is the Yellow Mustang for $45,000. The next most expensive car that's not on sale is the Black Charger for $41,700. And then comes the Eclipse, the Camaro, and the Sienna. So again, like I said, you set up the chain by passing in the input. Each item in the chain gets the output of the last function in the chain. So I can filter by saying, first of all, I don't want any of the items where the string sale shows up in the description. Then I can take that string and split it on the dollar sign character and make sure it's sorting by the price that's coming in. Then, since everything's still set up in the object array, I can map everything to a simple array. And here I have to take off the trailing comma that comes after the car name, then I can ask for only the unique values and then return the resulting value. That resulting value is an array of car names and that's what I logout to the result window. So, chaining can be very powerful and also help keep your code concise and expressive. Now, as you're working with chains, one of the things that you can do is tap into that chain and add some functionality to the chain along the way. So here I have an array of author records. Each author has an id, name, state, and an empty twitter handle. Down here, and again supposing that this data is coming from a different source than my data source for the authors up there, I have my list of twitterHandles. So this has an id and the twitter handle. So, the id values will match in the author's data as it is from the twitterHandles data. Now I have a function here and its job is to add in the correct twitter handle from the twitterHandles array up to the authors array. So, when this is called the authors array is passed in and I iterate over each author. Then I filter down to just the twitter handle that I want that matches the author that's showing up in the iteration. Once I have a match then I can set the value.twitter equal to the handle.twitter. Now this function works great against the authors array. So, I can use this to tap into a chain. Here I set up the chain against the authors and then I want to look for all the authors where the state equals Florida. Then I can tap in to add the twitter handle and then return the value. So to find all the authors in the state of Florida with their twitter handle associated to the objects is John Papa and John Sonmez.
Keys, Values, Pairs and Invert
Now, as you've probably noticed the keys function is pretty handy. In fact, I've had to use it a couple of times just leading up to the content in this course, because it makes working with objects so much easier to use and it's so simple too. Calling _.keys and passing in your object returns to you an array of the keys that are found within your object. And if it works for keys, it can work for values just as well. So, calling _.values returns an array of the values that are found within the object. Next in the list of functions that deals with keys and values is pairs. Now, when you call pairs against an object, what that will do is return a multidimensional array with the key and value pairs as an array, within the array. So, my log function here kind of flattens everything out so let's take a look at this in the debugger. So you can see that when pairs is called, what you have available to you is an array with two elements in it. And inside the first element is an array with the key and then the value. The second element is an array with the key and then the value. So, depending on how you need to work with your data, pairs can make it very easy to extract out both the key and value information from your objects. And the last function in this family of functions is invert. So if you have an object and you want to make the values the keys and the keys the values, you can call invert and it'll make that switch for you. So when I Run it you can see that by calling the property of Craig Shoemaker on my object, I get the value of name. This is even more clear when we take a look at it in the debugger. Now, you can see the original object has the key of name and Craig Shoemaker is the value, the key of state and California is the value. Once it's been inverted, now I have an object that has California as the key and state as the value. So, it basically just switches it around, it inverts the data within your object so that the values become keys and the keys become values.
Functions
Now, there may be a time when you're working with an object and you need to know how many functions or methods are associated with that object. Well, the functions function or the methods alias will return exactly that information to you. So, the code right here might look a little weird, but this is the way to calculate how many functions there are in Underscore. So when I Run this you can see that there's 106 functions in Underscore and that includes aliases and here's the full list.
Extend, Pick, Omit and Defaults
Now what extend does for you is it takes a source object and copies the keys and values over to the destination object and returns the destination object for you. So here I have an author, the name is Craig Shoemaker, and some contact info. So I've got a url and a twitter handle. When I extend author into contactInfo the extended object is all of the information put together. Now, one of the things that you want to be aware of is that overwrites are possible. So, we take that same example and adjust it just a little bit. In the author object I have a value for url. In contactInfo I have a separate value for url. But when I extend author into contactInfo, the results is that the url value has been overwritten from what is in contactInfo, given priority over what was in author. So make sure if you have any keys that match up in the objects that you're extending, that the data you want to keep shows up in the target. Now pick allows you to manipulate an object so that only the keys that you pass in to the pick function are the keys and values that will end up in the resulting object. So here I have my author object and all I'm saying is that I want the name and url data to come through in the resulting object. So, the picked object ends up looking like this. Since I didn't add the twitter key in the white list of the properties that I wanted, that was removed from the result of the pick function. Now, if pick allows you to work with a white list, omit allows you to work with a black list. So here I'm saying, I'm working with author, calling omit, but I want to omit out the twitter property and the url property. So, all that's left is the name property. So, if you have an object and you mostly want to keep the construction of that object intact, but just remove a little bit of data, omit is the way to go. The defaults function gives you an easy way to provide default values for objects that you're working with. So take a look at the defaults object here. You can see that I have active is true and the bio URL, which is the base URL for Pluralsight authors. Then I have my author object where I've got name, url, and twitter handle. So when I call defaults and pass in defaults and then author, the result that I get is an object that has the default values added to it, along with the original data that was found within that object. Now one of the things that you need to be aware of is that by calling defaults, it will overwrite existing values. So, when you take a look defaults that I have here, notice the URL that I have for bio, again the base URL for author bios. If you take a look at the author object down here, I have my full url for my Pluralsight author bio. Now, when I call defaults, you can see that the two properties and values that didn't exist in the author object that were in defaults, active and reviewer, show up in the resulting object, but bio is the data that's from defaults. So, all this to say that if you have an object that already has a value in it, you may not want to call defaults on it unless you're okay with the default value being copied over to that object.
Clone
The clone function gives you an opportunity to create a shallow copy of an existing object. So here I have my minion object and the name is Storm Trooper and I'll clone him in order to make a Clone Trooper. Now, you can see from the result that the Clone has the same schema as the original. Now one of the things you might want to be aware of is the fact that if you try to do a deep clone it may not work exactly the way you might think. In fact, it doesn't do a deep clone at all. It only does a shallow copy of your object. So let's take a look at this data here. I've got a minion, again named Storm Trooper. His duties are to Clean AT AT and Find Leia. Now, the clone is going to get the same thing. Except what I'll do at this point is change his name from Storm Trooper to Clone Trooper. Let me Run it and see what we've got. Alright, we've got the original named Storm Trooper, duties just as defined. And we have the clone named Clone Trooper, duties just as defined. So, let's come down here a little bit and see what else is going on. Then I go into the minion's duties and I push in a new value into that array, 'Fix Vader\'s Tie Fighter'. So here's the label for updating the minion's array and now let's take a look at the resulting data. The original, named Storm Trooper, has all the duties that he used to have, plus the new one of Fix Vader's Tie Fighter again, but so does the clone. So, all this to say that if you try to clone a deeply-nested object, any of the deep members of that object are still kept in reference. So, this is a handy function when you need it, but just be aware of exactly how it behaves.
Has
Now at first glance, the has function might seem a little redundant based off of what's already available in native JavaScript. Has takes a look at an object and will let you know if it has that property or function in it. Now that's all handled by JavaScript's hasOwnProperty function, but what the Underscore has function does for you is it protects you, just in case hasOwnProperty is for some reason overwritten. Now take a look at this object for a moment. I've got a property of name with the value of Craig Shoemaker and another property of hasOwnProperty where I'm saying, "I'm overwriting the native function!". Now this is doing just that. There's normally a function within a JavaScript object called hasOwnProperty. So let's Run this. When I call author.has and pass in name, that returns true because the name property exists. Now, if I try to use hasOwnProperty on that object, calling author.hasOwnProperty and pass in name, you'll see that the error condition is raised. And here it logs out that the call to the native implementation failed, because the property that I created in my object overwrote the function of hasOwnProperty that's natively found in a JavaScript object. So now, if I go to author and look to see if it has hasOwnProperty, that returns true. And when I go to execute it you can see that it returns the same text that I had set up in the object. So, has gives you a way to safely know that when you're looking for members of an object you'll be able to know with a certainty that those members do actually exist within that object.
IsEqual
Now we start to dive in to the series of is* functions in Underscore. So all of these functions will give you an opportunity to know a little bit more about the objects that you're working with within JavaScript. The isEqual function will look to see if an object is equal to another object. Now when I execute the code I'm doing some contrasting here a little bit. I have my author object, it has name and Craig Shoemaker, and then I go ahead and clone it. So I know there are two separate objects, but they have exactly the same data within them and exactly the same schema as well. So, when I look at author and look to see if it's == to clone that returns false. If I look to see if it's truly equal to clone, which it's not, because it's a separate object, that will also return false. But, when I call isEqual on it, I know that the schema or all of the keys and the values, and all the data is the same between those two objects. So when I call isEqual that returns true. Now this is really useful for Deep Object comparisons as well. Notice here I have author1, active: true, name is a nested object, first and last name. Author2 is the same thing, active: true, nested object, first and last name. So does == consider them equal? No, it doesn't. Are they truly equal with a triple equal sign? No, they're not. But, by calling isEqual you can see that even with a nested object that they're considered equal. But, as soon as I make a change to one of those objects, so here I have author2.name.first setting that equal to Dan and when I call isEqual on that you can see that now they're considered to be in-equal so isEqual returns false.
Is* Functions
Now the rest of the is functions are going to use my 'Big Array of Everything' and you'll see how I use this in a minute, but I want to go through the values that are in this array so you can kind of get an idea of the fact that I'm trying to account for just about everything within JavaScript. So I've got Infinity and --Infinity, null, and undefined. I've an empty string and an empty array, an empty object, and then this curious little notation here which is forcing the NaN value. I've got a regular integer, regular string, Boolean true and false, a Date value, a regular expression, and then a couple of arrays here. I have an integer array and an object array. Then I have an object that actually has some data in it. And then I also want to take a look at some DOM elements. So, I'll use just regular, standard old JavaScript to go and get the article element that's in this page and then I'll also use jQuery to do the same thing. And by passing in the indexer, I'm getting back the raw DOM element rather than jQuery object. Then I have a few functions. First, this is a self-executing function with parameters and then I have a self-executing function that doesn't have any parameters. And then finally, I have a function that actually does something. So, let's Run isEmpty and see what comes up from here. Now the thing that's most interesting about this is down at the bottom and you can see that there's some false positives that are returned from this. Really, you only want to use this function for objects and arrays. When you use it on some of these other data types, you can get some weird stuff going on. So, once you've had a chance to read that paragraph a little bit, I'll scroll back up so you can see exactly what's getting a positive here. So Infinity and --Infinity being empty, I'm not so sure, null that makes sense, undefined. But Boolean true and false being empty and Date and regular expressions truly aren't exactly what you're looking for. So, as long as you use this function the right way, you should be just fine. Now, if you want to find out if something is a DOM element, you can use the isElement function. And you'll notice here by going through the array, the only thing that returns a positive on that is the DOM object that's accessed directly or also through jQuery. Now, trying to figure out if an object is an array is a little more complicated than just looking to see if it has a length property. So, by running this you can see whether or not you are actually working with an array object. Now, notice it returns positive for empty arrays, actual flat arrays with regular values in them, and also arrays that have objects in them. And if you notice at the upper left that this is in the ECMA Script 5 specification so this should be native in all environments at some point. Now we say technically everything in JavaScript is an object. So, what's interesting about this function is not what it returns positive on, but what it returns negative on. So you see, there are certain values that are not considered an object at least by this function. Things like null, undefined, empty strings, integers, and even full strings. But arrays and even functions are items that are considered objects by Underscore. Now, if you remember from earlier in the course where I talked about the two array function, how that's often used with function arguments. Well, function arguments operate a little bit differently than regular arrays and just about any other object in JavaScript. So, the isArguments function is useful if you need to know at some point in your script whether you're working with an arguments object or not. So, as we take a look at the results, the only positives that are returned for isArguments are the functions that return arguments that have values in them and also empty arguments. So either way, whether you actually have values in your arguments or not, isArguments will return true for function arguments. Now one of the concepts that I keep coming back to is the fact that everything in JavaScript is an object and what makes functional programming so powerful is the fact that you can pass functions around, just like you would a variable or a numerical value or anything else. So, sometimes within your scripts you'll need to know whether or not you're dealing with a function or some other type of object. So the results that come in for isFunction only bring a positive for an actual function. And if you take a look at the last item here in the array, it's a function that's just operating console.log. It's not necessarily returning any value, it's just a function in and of itself. For isString we can take a look and see that the only thing that produces a positive value for isString is either an empty or a filled-out string. Now, if you've got isString you obviously have to have isNumber and I just realized there's something that I didn't have in this array that I needed for this demo. So, you'll notice I added a floating point number here at the bottom. So let's Run it and see what kind of positive results we get. So we get Infinity, -Infinity, NaN, which interestingly is a number, it's just a special type of number in JavaScript. Integer and also Floating Point Number returns a positive result for isNumber in Underscore. Now, not only can we tell whether or not something is a number, we can also find out whether or not it's a finite number. So, what returns positive on this is Integer and Floating Point for isFinite. The isBoolean function will return whether or not our value is a Boolean value and this returns true only for the Boolean true or Boolean false values. Scroll down here and you can see that that's the only thing that returns a positive value. The isDate function looks at an object and determines whether or not it's an actual, in real JavaScript date object. Running this against the bigArrayOfEverything you can see that the only thing that returns a positive is the actual Date object. The isRegExp function will determine whether or not you're looking at a regular expression. Now you may have noticed within the bigArrayOfEverything that the regex value looks a little odd and that's just because of how it's being rendered on the screen. But this is a true regular expression. In fact, let's inspect element and then we can take a look at the script that's being brought in and you can see that right there is a regex. It's just being rendered on the screen a little bit strange from the code viewer. But, just like we would probably expect, the only thing that returns positive for this function is the regular expression itself. Determining whether or not you have an actual number or not is very valuable. So, the isNaN function will find its way into a lot of uses into your scripts. You might ask yourself, well what's the difference between what Underscore does and what the native implementation is? According to the documentation, it's not the same as the native NaN function, which returns true if a variable is undefined. And the Underscore version will not do that. Also, if you need to add this in to some sort of chain or maybe a composition of something that you're doing, using the compose function, having it exposed through an Underscore function is really helpful. Because then you can tap in to that type of construction. So the differences between this and the native version are nuanced, but again, depending on how you're using it and what you need it could become quite valuable. So when we Run it against the array you can see that the only positive it's returning is against the actual value that is not really a number. Now, we're always checking for nulls. So, having an Underscore function that is able to handle nulls is quite valuable. So when we Run it against the array, get a positive result only for the actual null value. And a close cousin to our friend the null value, is the undefined value. So, running it against the array, the only thing that's going to produce a positive result in this case is an actual undefined value within JavaScript. So there you have it. That's the roundup of the is* functions in Underscore. And my Big Array of Everything probably isn't everything, there's probably more that you could probably think of in order to add into that array in order to make the testing a little more complete. So, I encourage you to do so if you have any questions about how these functions might behave against different types of data and different types of objects. But, the bottom line is most of these are pretty reliable in doing exactly what the function name expresses that you might expect it to do.
Summary
Working with JavaScript objects has never been easier than when using the support provided by underscore to extract and manipulate, not only data, but also the shape and schema of JavaScript objects. Now join me in the next module where I show you how to use underscore's utilities to do everything from generating random numbers to client side templating.
Utilities
Introduction
In this module, I'll discuss the final set of functions found in the Utility section of Underscore. Now make sure to stick around for the last module in the course while I'll take you through an integration demo where you can see many of the functions you've become familiar with up to this point working together in a more real-world implementation. For now though, we'll discuss the series of utilities that round off the effectiveness and ability of Underscore.js.
NoConflict
The noConflict function comes into play when you're working with other libraries that may be using the underscore character in order to establish their API or if you want to use the underscore character for some other reason within your application. Now, noConflict gives control of the underscore variable back to its previous owner and then the return value of noConflict is a reference to underscore. So here within the demo you can see I'm calling _.noConflict and sending the u variable equal to that. So now, after calling that command, u is the Underscore library instead of the underscore character. So now, when I execute the each function I get the results in the results window using the u character instead of the underscore character. Now, I'm using Underscore under the hood for my code viewer so I have to do things a little bit manually within my iterator. But, in the end you use noConflict when you want to make sure that Underscore won't have a conflict with any other libraries.
Identity
Now to be thorough, I have to include a demo here for identity. This has to be one of my favorite functions in Underscore and it has to do with what you find in the docs. So, right here it's got Straight from the docs. This function looks useless, but it's used throughout Underscore as a default iterator. Now, let me explain what that means. Well, first let me explain what it does. What identity does is it takes in the value and it returns the value. So, in my code here when you see does author equal _.identity(author) and that returns true. That's because the identity function is simply turning around and passing author back up. Now why in the world would the library need something like this? Well, like the documentation says, it needs a default iterator. So, if you're doing something like map or each or you're running one of these functions that has an iterator in it, but you don't provide an iterator, it needs something to be able to run at that point. And so, it will use identity in order to just return what it was before. That way, it doesn't affect any of your data. So, identity seems a little silly, but when you understand the purpose and why the developers have it in there, you can see that perhaps as you build your own functions, that maybe you mix into Underscore and I'll show you that in a few minutes of how you can do that. But maybe, as you build your own functions to work with these sets and build up some functional resources you might find some use for it too.
Times and Random
Now, if you need to do something a specific amount of times, there's a couple different ways that you could do that. One of the ways would be to build up a four loop and make sure that whatever you're doing happened with the right amount of counts or what you could do is use the times function in Underscore. Now, this uses the chaining syntax, like my little comment says. But, with times what you can do is you can pass in the number of times you want something to happen. And then you can create an iterator function to do whatever you need to do. So here, I'm simply logging the index, but with that iterator function the argument that's passed into the function is the index so you have that available to you to do whatever kind of processing that you need to have done. Now, if you need a random number, Underscore's got you covered. Now remember JavaScript has ways of doing some of the stuff that Underscore does. But, if you need to set up a chain or you need to set up something with the compose function or whatever you're doing, if you need a specific way of handling that within Underscore some of these things are nice to have as a part of the library. So, there's two ways that you can get random numbers. The first one is just to pass in an integer, which is the maximum value. So, here in this first instance, it's telling Underscore to generate a random number between 0 and 10. If you want to be a little more restrictive you can pass in a range. So, you have the begin value and the end value or the minimum value and the max value. And so, in this instance it'll generate a random number between 50 and 1000.
Mixin
Using mixin allows you to extend Underscore with your own functions and your own implementations. Here I've created a mixin for trimEnd. So, I pass in an originalString, pass in the string to trim, and then just do a substring operation against it in order to return the final result. Now notice the way you want to set this up is you call the mixin function and then you pass in an object with a key of whatever you want that function name to be and then the value of the actual function itself. Now when you go to call it, you can use either the object-oriented approach or you can use the more functional approach. Either way, you get the same result. So, what about another implementation? What about Reverse String? Here's the same thing, I'm calling mixin, I've got my hash or my key value of reverseString. The function here implements what I want it to do and then I can call it either of the two ways that is comfortable. So these are fun, but there are some other things that you might want to consider doing maybe sum, average. Here, I created an implementation for sum. Called mixin, passed in sum, created a function for it. Here I can call Underscore's reduce in order to reduce my array down to a single value. Now I'll look at the number that comes in to see if it's an actual number or if it's an object. If it's an number I'll just use that value. If it's an object, then I need to take a look at the key argument to find out which property in that object has the value I'm looking for. Then I can add it up to my memo and return that final value and that allows me to sum up numbers. So here I have my object-oriented approach where I can pass in an array and call sum or I can use my functional approach against an array of objects and I just pass in the key as the second argument. So, there's a lot to be gained here by giving you an opportunity to mix in your own implementation with the Underscore library.
UniqueId
Now, when you're generating elements for the UI, often the DOM elements that are created need to have a unique ID. Now, you can handle that manually or you can use Underscore's uniqueId function in order to help you generate those values. So, you can either pass in a prefix or you can just call the function by itself. Here, just by calling the function I get 9, 10, 11 or I have the prefix of 12, 13, and on down the line. When I Run it again you can see that it's keeping a running count of the values that are used on this page. So that you generally know that you get a unique ID every time you call the function.
Escape and Unescape
Now often times you want to escape a string in order to make sure that you're either dealing with non-executing code or protecting against malicious attacks or you just don't want something that someone types into an input field in your web page to affect the markup in any way. So, by calling escape, I'll Run this and you'll see that you need to take a look at the console to see the results. You get the same lines of text as from above, the good, the bad, and the ugly with the HTML entity for the ampersand and then the escape characters for the HTML elements, as well as the markup for this HTML pre-element. And if you can escape a string of course you need to unescape that string. Now, I'm using the escape function within my code viewer here so you're actually not seeing the real code. So, let's open up the markup and you can take a look and see what's really here. So, this is the code that should be printed up in the code viewer and now when I Run, we can go over to the console. We get the unescape strings, which bring them back to their raw format.
Result
The result function gives you some flexibility when you're working with objects. Sometimes you'll have members of an object that are property and sometimes they'll be members that are functions. And what result does is whether or not it's a property or a function if you call result on that member for your object, it will either return the value of the property or execute the function and return its value. So you can see when I call result on author and pass in first, it's going to the first property and returning Craig. But, when I call result on author and pass in getFullName it executes the function of getFullName and returns to me the concatenated string of my first and last name. So, as you're passing around functions and objects around your scripts, you may not know exactly what the object is that you have and when used with other Underscore functions like keys and functions and getting all the metadata about objects that you're working with, you could very easily find yourself in a situation where you need to use result to get the value of something out of an object. Because you won't know necessarily until run time exactly what you're trying to execute.
Template: Part 1
So now we've come to the section on Underscore templating. There's actually quite a bit available to cover within templates, so I've got a couple different pages here that each have demos on them. Now, you can certainly find JavaScript libraries that focus specifically on templating or binding or any part of the equation when it comes to rendering information out on the screen. But, Underscore has some simple yet powerful support for templating. So in the easiest sense, I can have an author object and bind it to my template. And you can see here the result, Craig says, "hi there!" Now, the result is the actual HTML that's generated from the template and at this point I'm calling template and passing in the text of the template and then as the second argument to template I pass in author. Now, the delimiters for template are these ERB-style delimiters. So, all you need to do is open up the delimiter, place the equal sign, and then have the object property that corresponds to the data object that you pass in. So here, I'm passing in name. So after running that you have the raw HTML, which you can append to a DOM element on your page. So, that's the most basic sense of how to run a template. Let's take a look at it as an object array and there's another nuance of this demo that I want to show you as well. So, here's the object array that you're probably pretty used to seeing from other demos within the course. And then I'm creating a data object and just nesting the authors in the data object. From there I'm creating my template and notice here within the template, you can execute JavaScript code. Here I'm just calling another Underscore function, each, and I'm iterating over the authors and creating an iterator, which creates the list items for the authors. So the final result here, is an ordered list with a start value of 0 and it goes through the authors and creates that ordered list. Now, this time instead of executing and applying the template all at once, here I'm passing the template into the template function and returning the result to a function called applyTemplate. This is actually the compilation step where Underscore takes your raw template string and compiles it into a regular expression and some other magic in order to make the template perform well. So now, I can call applyTemplate by passing in my data object and the result of that is the HTML markup, which then I log out to the result window. Now, sometimes you're dealing with data that needs to be escaped. So the syntax for escaping values within Underscore templates is to use the dash symbol in the delimiter rather than the equal sign. So, the idea behind this demo is that my demo object would be maybe some documentation that needs to show up on the Underscore site and it shows how to use the template function. So, I'm passing in some HTML markup in this string so I need that to appear on the page just as it shows within the string here. Then I'll pass that in to an Underscore template. Opening up the debugging tools and we'll Run this and you can see the result. So right here where I'm using the equal sign and the value is unescaped, you can see for the first item in the log here that the HTML markup remains unchanged. But, if I run it again and use the dash sign instead of the equal sign, as I log the result back out to the window, you can see that all the HTML has been escaped out. So now I have a safe string, which I can render out onto the page.
Template: Part 2
Now sometimes using the default delimiters can get a little dicey, especially when you're executing JavaScript within your templates. So, this demo's much the same as the one I showed you previously except instead of using the regular delimiter, I'm using the print function in order to render out content into the template. So when I Run this, you get a nice little message. And so really, the only difference here is the fact that I'm using print instead of the delimiter and the equal sign. Now what if you don't like the delimiters that come stock with Underscore? Well, you can certainly change the template delimiters. Now, if I wanted to do something completely ridiculous I could change the delimiter to be da-codez and you'd do that by adding in the template settings and giving a regular expression into the interpolate key. Once you've set that, then anytime you do templating within Underscore you can use whatever type of delimiters you've created. Some people like to switch this over to be the curly braces like you find in Mustache.js templating engine. Now, one of the ways that you can improve performance is to change the scope that's found within your template. By default, Underscore uses the JavaScript with statement, which sets the data object you pass in as the default object for the template. So let's take a look at the templateLocalScope template for a moment. Notice how I'm calling each on a collection called people. Now let's take a look at the variable scope down at the bottom. Now I'm calling each on data.people. So when Underscore runs the local scope template it binds the data object that you pass in using the with statement. Now, this makes the code easier to write and it makes it pretty performant, but if you're dealing with a large set of data you can improve that performance by passing in a settings object, which tells the template the name of the variable that you're working with. And that's exactly what I'm doing down here in settings. You see I'm creating this object here. I have the key of variable and I'm saying it's data. That matches the data.people, which shows up in the variable scope template. Now, for my view model here, I'm just using a library, mockJSON to generate from a template 5000 names, first and last names. So, this is kind of a big dataset and when we run it you'll be able to see the performance difference between the two. Let's Run it to get the results and now I'll open up the console and you can see that the local-scope template took 5 ms to execute, but on that same data with basically the same template the only difference between the two templates is the fact that I have a named data variable and the other one is basically assumed using the with statement. So, the only difference between those is that small detail and that improved performance by shaving off 4 ms. Now, 4 ms isn't a lot here, but as you get into more complex UIs and perhaps dealing with larger amounts of data, it can certainly add up.
Template: Part 3
Now Precompilation has an important part of the process because it generally takes the most amount of processing time to execute. Here my data object is say, some sort of documentation. I've got a title and a description. Now, you can't see my template. In fact, let's take a look at the markup so you can see what the template looks like. So here's my big template. I have a place for my title, description, and then a whole bunch of gibberish. But, if this were regular content or you had some other large-type of template, this could very well represent something that's what you might find in the real world. But a template this large will take a little bit of time to compile before you can use it an apply your data to the template. So now I'll Run this code and we can take a look at the console and see what's happening here. Now here, I'm compiling the big template and that took 5 ms. But once that template is compiled, I can go ahead and use it over and over again. So when I render it for the first time, that only takes 2 ms. When I render it for the second time, that only takes 1 ms. And this doesn't only apply to big templates. If you have areas of your page that you need to render over and over again, what you don't want to do is recompile that template over and over again. In my integration demo I have a template just for a row within a table and I use that over and over again as I'm iterating over data. So, precompiling your templates is something that you definitely want to pay attention to. And in fact, fellow Pluralsight author Liam McLennan, is a part of underscorec and you may want to check it out if you end up using Underscore templates a lot in your applications. Alright, now let's take a look at Sub Templates or what I'm calling logic-free templates. When I Run this it's not really all that exciting as far as the result is concerned, but what I'm doing that's interesting here is removing all of the JavaScript out of the strings that are within my templates. Now the reason for doing this is that because it's really difficult to debug JavaScript that's been compiled into a template. So, in order to get this list I'm doing it in two steps. The first thing that I'm doing is rendering the parent and then I'll render the child. So the template for the parentRenderer is my ordered list and as you can see here from the markup, it's basically just the stubs for the ordered list and where the items placeholder is is where all the list items will appear. Then I have a child template. What that will create for me is a series of list items with the data that's coming in from the data object. So, in order to render out this list of names, the first thing that I want to do is render the children. And I can do that by running the renderChildren function where I'm passing in my data object of authors. Now I'm setting up my result as an empty array so that as I iterate through each one of the authors, I can just push in the output that comes from my childRenderer function, which is the compile template for my children and this returns the markup that I want to appear in the array. So, it's basically list item, name, close list item. When I do that for each one of the authors all of that is in an array so I can join it with the line break character and I set that result equal to children.items. So now when I pass children into my parentRenderer, going against the template up here, it's looking for the .items property and so when it finds that it takes that whole list of list items that was generated by the child template and injects it into the unordered list. So once all that's done I can take the result, which includes the parent and child markup and attach that into a DOM element. So again, the value to doing things this way is that while you're keeping discrete steps in building up your templates, it makes it much easier to debug and really much easier to develop. Because you're working with JavaScript code as JavaScript and you're working with templates only as strings. And keeping that type of separation of concerns can really be valuable to you when you're using this in the real world. Now speaking of more real world-type of situations, let's take a look at what it might be to use a template with a view model. I'm going to go ahead and Run this just so I can generate my button. And that's what that first line in a listing does is just adds the button to the markup there. So, I've got a view model that I'm using with this page and I've got some data within that view model of my authors array. Then from there I want to be able to display the authors out onto the page. Now the first thing that's happening is I'm compiling a template for rendering the row and then compiling another template for rendering the root. Now, I don't want to have to maintain this template within JavaScript so I've put it into an HTML element. Let's take a look at it. The template for my root is put into a script tag with a type of text/template. What this does is it allows the browser to be able to handle the content within the script tag and basically ignore it. So, since it's not executing as text/javascript or anything else like that, the type is just template. It completely ignores what's in here. But, at the same time most IDEs will often support the markup that's found within these tags. So, you get the support that you're used to when you're writing regular markup. So the root of my template is to create a div tag and then create a table. I've added some Bootstrap classes to it and then just like I did with my last demo, the logic-free templates, I'll take the result of the markup of the rows that I'll generate and inject it into this template. So, that's the root template. The rows template themselves, here are just individual rows. And you can see that I'm creating it to say that a person's name, lives in, and then the state that they're in. So what I'm doing up here in displayAuthors is using jQuery to reach in and grab the markup that I placed within those script tags and add that as the template. I'm compiling the template and now I have the renderRow and renderRoot ready to use with whatever data I pass it. In order to handle the markup that I'll generate, I'm creating an empty array for the rows. And that represents the markup fragment that I need to pass in to the root template. So, I'm creating a fragment object and I'm adding a key of rows and then I'll take the HTML that's generated for each of my rows and add that in to the fragment. And then I have this last variable here declared for the final markup that I'll render out onto the page. So here I'm using Underscore's each to say that it's going through the authors. this.authors points to the authors array up here and as it iterates through each one, I'm calling renderRow on the value. Now, if you remember from the template in renderRow, it's looking for the name and within each one of my data items, I have object.name in order to print that out. It pushes a new item in each time I iterate through an author and so once that completes I can take my rows array and join it with a new line character. Then I can take that fragment, because fragment.rows now has all the markup I need for the rows in the table and I can render that into the root. Then you can see right here the root template is looking for the rows property. So that lines up just nicely and then once that's done executing, I have the full markup for my table and so when I click on Show Authors, I get this nice, styled table using the data that I had within my view model. So, Underscore templates have quite a bit that's available to you in terms of being able to affect performance and making it easy for you to develop with. Generally, there are a lot of other frameworks out there and JavaScript libraries that do templating specifically, but if you need something that's fairly simplistic, the Underscore templates shine in giving you the power and ease of use that you need.
Summary
With the grab-bag of utilities in Underscore you can easily extend the Underscore library, control markup on your page, and even handle client-side templating. Now join me in the next module, where I take you on a guided tour of using Underscore by example in a more real-world context, where together we'll build a sales summary report for a real estate company.
Underscore by Example
Introduction
Now that you've had a chance to see Underscore functions working in sort of an atomic fashion, kind of seeing what the arguments do, seeing what the returns values are. I want to show you now what it looks like to use it in something that's perhaps, maybe a little more real world. Now, this is still a mock company with mock data and all that kind of stuff. But the idea is, is that this page is set up to be constructed in a way that you might do it in an everyday scenario. So, welcome to CraigHomes. This is a sales report done at the end of the year, say for the Management Team. Now the first thing they want to know is the sales by month in millions. Now, you'll see that the data that's being fed into this page are individual records of sales. And so I'm using Underscore to create aggregations in order to make this table happen. On top of that I'm doing some comparison against plan. So, for this report there's a business rule that says, anytime the sales were over 7 million dollars in a single month, they're above plan. Anytime they're under 7 million dollars, they're below plan. So the items colored in that light-gray background show that they were above plan for that month. Then there's the Quick Facts. The highest sale of the year was $672,542, lowest $219,442, and on average houses sold were around $465,406. You can see a list of all the properties that were sold, all 200 of them, which you can see down here. And you can even go in here and filter the properties. Let's say we want to look in a specific county, like Riverside County, and find everything that shows up in Temecula. So I can filter based off that. You see now there are two properties down there and we get those two properties that show up. And I think I have like, I don't know, five to seven sample images and wouldn't you know it, within my filter the two records that show up have the same picture. Well, we can clear that filter and you can see that now we're back to all 200 of those properties. As we scroll a little bit further down, you can see we're able to send that information to Marketing and also send to the Manager. So, the interaction and the data within this page is fairly simplistic, but I'd like to show you how I built it using Underscore.
Markup Overview
Now, as I take you through the implementation of this sales summary, you'll get a chance to learn about a number of different Underscore functions and how they're used in context on this page. Before I get into that though, let me just give you a brief summary of the markup that's in the page so you get an idea of what the overall construction is for the sales summary. First of all, I'm using Bootstrap in order to handle some of the layout concerns. So you can see here I've got the CSS file, which I've included and also I have some Bootstrap classes applied to elements throughout the page. This section here, is the header of the page. Then in the middle I have two content areas. One is for the table, that's the sales summary and the other one is for the list of products. I'll be getting into detail on those sections pretty quickly. Then I've got a real simple footer and also my JavaScript references. The scripts that I use in this page include jQuery, a library called mockjson, which I'll dig into in detail next, the bootstrap scripts, and of course underscore. Then the custom modules, which I've created this page, include some customizations to mockjson, mixins that I've created for Underscore, my data management module, a module just for rendering templates, and then the view model for this page. Now, as you can see down here in this script block the view model that I'm using is declared up here in viewmodel.js. So the only code that I have actually in this HTML file is where I'm handling the jQuery ready function, calling bindAll on my view model because I want to make sure again, that the this pointer routes to members of my view model object, and then I call init on my view model. Now the init function is where everything ties together pretty quickly. So before getting into that I first want to show you a little bit about the mockJSON library.
MockJSON Intro
mockJSON is a jQuery library that makes it easy to generate random data for testing and prototype purposes. It's perfect for this application because when you download these files, you'll get the feeling that you're working with data that comes from a service or perhaps a database, but it's not required to set all that up in order to make this page work. What's nice about mockJSON is that you can define templates to shape your data and even create custom keywords, which give you an opportunity to provide seed data that's then used randomly per your direction. So, when we take a look at the template here first I'm saying I want to create a list of 200 properties. Now the way mockJSON works is you can provide a range to show up right here after the pipe character. If I were to pass in something other, say 0-200, then it would create a random number of properties between 0 and 200, but I want exactly 200 properties so I'm passing in 200-200. Then I'm saying I want the id property, increment by 1 each time and I'm giving it a default value. Then within the template I'm using some keywords. So, image is a custom keyword and I'll show you how I implemented that in a moment. For streetAddress, I wanted to make sure that the street addresses looked kind of realistic so I didn't want any 0s to show up in there, so I have a keyword that will inject the first number. And then there's Native Keywords found within mockJSON and so I'm using number three times here. Then I have another custom keyword of STREET_NAME where I've provided a list of street names that I can randomly choose from in order to place into streetAddress. Same goes for CITY_NAME, and then the zip code, I'm seeding it with 90 because most zip codes in California, at least Southern California, start that way and then three numbers. COUNTY also is a custom keyword, which I defined. And then, I'm generating some random data here for bedrooms, bathrooms, saleMonth, saleDay, squarefeet, and even price. Here I'm giving the ranges after the pipe character. So, bedrooms can be any value between 2 and 6, bathrooms 2 and 4, and on and on. I'm just providing some default values here, but those'll be overwritten when the random data is generated. Then finally, I'm using some built-in keywords for mockJSON where you can generate an uppercase letter and some LOREM_IPSUM text. Sometimes it's long, sometimes it's short, it just depends on how the randomization comes out. So this template, when it's used from generateFromTemplate, creates an array of 200 properties based off the constraints that I've given it and so you can see, on the running page, how this shows up within the list.
MockJSON Customizations
Now mockJSON comes with a really useful list of keywords. So you can get numbers, you can get dates, you can get email addresses and names and things of that nature. But sometimes you need something that's a little more specific just to flush out the data that you'll be using within your application. So here, I'm creating some custom keywords so that as random data is generated, mockJSON will randomly choose from items within the arrays based off of these keywords. So, for STREET_NAME when it generates a record, it could choose anything between Wallaby Lane, Sixth Street, and even Crazy Way. So, this just maintains a list of street names that it can use when it generates those objects, and the same thing for CITY_NAME. So, here are some cities around Southern California and also some counties. Now, obviously this is all random data so there's times when a city name will appear associated with a county that doesn't make sense in real life, but that's okay, this is just random data. So I created one for CITY_NAME and also for COUNTY. And I also created one for FIRST_NUMBER and for IMAGE. Again, the reason I wanted to do this with FIRST_NUMBER was because I didn't want 0s showing up in the first character of a street address, a little nitpicky I know. And then for IMAGE I have some sample images and I just wanted an easy way to be able to pull out a URL for those images. There's obviously a number of different ways that you can handle that, but this was just one way that I chose to do it. So, this module here creates all the customizations for mockJSON that's required and in fact, I don't know if you noticed up at the top, but I'm creating the mockJSONData variable and setting that equal to a self-executing module. So, as soon as I include this into the page, this script will run and it will customize mockJSON for me, as I need.
Mixins
The next module that I'm bringing in are my mixins. Now, the first mixin that I'm defining is numberWithCommas. So I have a regular expression that will take a number and create common groups every third digit. This is really useful for rendering out currency. Also, just as I showed you during the mixin demo, I went ahead and included the sum function here. This is really handy because I'll be chaining some functions together and adding sum to the mix really helps out a lot. Now like I did with numberWithCommas, the whole idea behind Underscore, chaining, and functional programming used with strings can be really useful. Underscore.string is a project that includes dozens of different functions that are really useful to use with strings. They have a number format one, they have capitalize, chop, clean, trim, on and on and on. If you want to find out more about Underscore.string, check it out at this URL here.
Data Module: Overview
The data module is where a lot of the work is going on so I'll give you an overview and then I'll dive into some of the specific parts of it. So first, I just have an array that has all the month names. Now, the month names don't appear as they are here in this array. I'll manipulate those names a little bit before I display it out on the screen. Here planTarget defines the value that Management wanted to hit, which decides whether or not sales were on plan or not. So, I'll use this to evaluate whether or not to add a CSS class to elements when I'm rendering out the summary table. Then I have a sub module, which will create the abbreviated months, a sub module, which handles the properties, and then an object that handles aggregations. This module uses the revealing module pattern so what's exposed from the module is the aggregations, months, planTarget, monthsAbbrev, and the properties list.
Data Module: Months
First let's talk about the abbreviated months. The way I've set this up is to be a sub module so that when you go to data.monthsAbbrev.get and call that function, you'll get the data that's created by this function. But at the same time, I made it a sub function so it's cached. It's a little overkill for what I'm doing right now, but at least this way if you call monthsAbbrev more than once, it doesn't have to recalculate, it'll just grab the cached version. So the way this module works is that the months that are available up here in this array are passed into the module down here. Now they're made available within the function arguments at this point and then I create a get function. If the results are null I'll generate the value that goes in the results. So what I'll do is map the months so that I'm getting just the first three characters of each month. So here, map is giving me a chance to transform the data that's coming in as the months array and just provide the abbreviated versions of it. Now of course, this is a demo application so I just could have created the array of months with three characters at a time, but this is an idea that gives you a chance to see of why you would want to use map. Often times, data comes into your application and you don't always have an opportunity to change things on the server end or maybe it's just easier to do it within the scripts. So this shows you one way in which you can do that. So once I have the results, that's returned back up to the caller. When the function data.monthsAbbrev.get is called, it'll return an array of the abbreviated months' names.
Data Module: Properties
Next, I'll discuss the sub module for properties. Now, much like I did with the months, I'm creating a cached version of the properties, just so that when a call to getProperties is done more than once the information's not being recalculated. And particularly in this case, that's important because I'm dealing with randomly-generated data. So, if I need to get that information more than once I need to make sure I'm working with the same data that was generated in the beginning. So, I'll scroll down to the get function. And you got a preview of this when I was discussing mockJSON earlier in this module. Here the get function first looks to see if the data variable has anything in it. If it doesn't, then it generates from the template using mockJSON the list of 200 properties. Then once that's done, it returns the properties that are generated from mockJSON. Now notice the array as it's generated from mockJSON is found at data.properties because the template was declared with properties as the name of the array here. So down at the bottom, to return the array, I need to return data.properties. So now that we can get the properties, it can be used a number of different ways. Let's go back up to the top of the module and you can see that there's a function here for filterBy. filterBy accepts a filter condition and then I can use Underscore's where function in order to filter the properties based off of the condition that's passed in. Now remember, where will take an object literal. So you can search the data that's passed into the where function based off a number of different conditions that you pass in to the function. So, I could be looking for something in a certain county and also in a certain city. And this will handle that nicely. So, once the data is filtered I simply return that value back up to filterBy. Now the data that's generated for the properties each has a county associated with it. So in order to get the list of counties within my data, I can call Underscore's groupBy passing in all the properties and telling it I want to group by county. Now remember, the way that Underscore does grouping is that it'll return to you an object where the keys are the criteria that you used in order to do the grouping. So my object will have a key for Riverside or Orange or San Bernardino. So, in order to show just those counties up on the page I can use the keys function to extract out those values, sort them, and then return them up to the caller. And the same approach is used for getCities. I can group the data source by cities, extract out those keys, sort them, and then return it up. So the properties module, which is actually a sub module of data, also uses the revealing module pattern. So the only thing that the caller will be able see is get, which gets all properties, getCounties, getCities, and the filterBy function.
Data Module: Aggregations
The last section of the data module are the aggregations. Underscore really helps in making aggregations easy when you're working with raw data. Starting down here, I'm passing in the whole properties collection to my aggregation object by calling properties.get and passing it in to aggregations here. Once I have those available, then I can begin to calculate the highest price. Using Underscore's chain syntax makes this really easy. So I can take a look at the properties, pluck out the price, find the max value, and return that value. If I want to find the lowest price, basically the same thing except here, I'm chaining on properties, plucking out price, finding the minimum value, and returning that. If I want to find the average price, I can chain on properties, again pluck out price, call the sum function, which if you remember is a mixin that I created in the mixins module, and then grab that ultimate value. Once I have the sum of all the prices then I can divide it by the size of my properties collection, which gives me the average and then I'll just round the final result so it looks nice when I show it on the page. Looking at totalSalesByMonth is pretty easy actually. If I take the properties and group them by sale month, and then go through that collection using the each function and sum up the price found in that group, then I'm very quickly able to build up an object that has the total sales by month. And here I'm just reusing the same object that was created by groupBy and just injecting the sum back into the values of those keys. Once I have those totals, I can return them back up to the caller. Now for monthlySalesSummary, I just take the total sales by month and do a little mapping here. Now the sale prices for these homes are in the hundreds of thousands of dollars. But if you remember from the summary table, I'm just showing the summaries in just a few digits. So, in order to make this happen I'm mapping the total sales and doing some calculations on them, so that I get the type of summary value that I want. Then I can return up those monthly summaries, which the view model will use to inject into the table. So with the months, formatted months, the properties, and aggregations that rounds out all the functionality that's required for the data module.
ViewModel: Summary Table
Now inside my view model, the init function sets everything up on the page. So one of the goals is to prepare all of the templates ahead of time. So, I only want to be accessing the DOM to extract those templates out once. And I also want to make sure that I compile my templates only once. So I'm doing all that right up front, just to make sure all that work is done and out of the way. The other thing I'm doing is selecting a number of the different DOM elements and setting them aside into variables, just again, so that I only have to do DOM selection one time for each element that's required. So starting at the top of the init function you can see that I've got a variable for markup. I'll use this over and over again with my templates in order to inject the final markup that's generated into a DOM element. Then I can go to my data aggregations and generate the monthlySalesSsummary. I'll show you how I'm using that in a few minutes. And then I have a variable for my quickFacts. And that just shows the highest sale, the lowest sale, and the average sale, which will end up being bound to a template in order to display on the screen. Now, if you remember from the demo I'm able to filter the properties list in order to look and see which properties were sold during that year. So when you filter the properties there's a County list, which is available, which lists all the counties and there's also a City list, which lists all the cities. So these variables here just hold the HTML select elements so when I get the contents to inject into it I can do that very easily. Then there's also the main propertiesList, which you can scroll through and see which properties are sold and also the propertiesCount, which shows up underneath that list. Now what I want to make sure to do is only hit the DOM once in order to extract the markup for my template and I also only want to compile that template once. Once the template is compiled then I can use it over and over again by passing in different data. So noticed what I've defined here as the thRenderer or the table header renderer. Let's take a look at the markup so you can see what that looks like. Right in here is the template and you'll notice all I'm doing is creating opening and closing th elements and injecting the value that will show up. And this is where the month names show up within the table. Back to the view model, I've got another one for my table data WithClassRenderer. Again selecting that and compiling the template. That template looks like this. I'm creating a table data element and then I'm passing in the className that I want applied to that element and injecting the value that needs to show up within that table cell. So those are the two child templates and down here, the "sales-by-month-list-container" is where I'll inject in what's created from the header template and the td template. And I put comments in there so you can see where that markup will be injected. Using the thead and tbody elements and adding ids to them makes it very easy to create a nice, well-structured table. So let's take a look at what's needed in order to render out the summary table. Here, I'm generating some markup, which is handled by calling renderer.renderCollection, I'm passing in the source data to it and I'm also given the renderCollection function the renderer that I want to use. So this.thRenderer is the compiled template for the table header. Now let's take a look at the renderer module for a moment so you can see how that works. Here's an instance where, in JavaScript you're given the opportunity to pass around functions makes working with a utility object like this very easy. So my renderFunction takes incoming data and simply applies the renderFunction that I pass to it. So this isn't doing anything really magical at this point, but I added it just for consistency sake. The one that really helps me out is renderCollection. So, I can pass a collection in and then pass the compile render function and it'll go through and iterate over each item in the collection, generate the markup using the rendering function, push the result of that into my array, and return all the markup from that array by joining it with a line break character. So this is exactly what you saw me doing in some of the previous demos except I wrapped it up into this function so that I don't have to repeat this code over and over again when I'm trying to work with my templates. Again revealing module pattern, there's nothing else in here, but I'm exposing out render and renderCollection as the public methods for this object. So when we come back to view model you can see that as I'm using renderCollection, I can pass in different compiled templates and it will do the rendering for me. So once I have the markup for my summary table, then I can select the table header element of that table and if you remember, that's right over here, this thead element "sales-by-month-thead" and so I want to select the child element of tr in order to inject all the th elements that are generated. And once I have that element I can set the HTML equal to the markup that's generated. Now the next thing that I need to do is take a look at the results of the monthly summary and decide whether or not I need to provide a class name in order to help decide how I'll color the background of the table. So here I'm using the each function to go through the monthly summary data and then adding a property of className and deciding whether or not it's above the planTarget or not in my data module. So, if it's greater than 7, which was the value that's in planTarget, it'll add in the className of above-plan. If not, it'll just be an empty string. So here's that code in the debugger. When you take a look at monthlySummary, I have this object array here and you can see the value is 4.69. There's no className associated with that yet, but after I iterate over each one here in this operation all of those objects will then have a className property. So now when we take a look at monthlySummary you can see that the className is nothing for this one, because it's under plan. For this one it's above-plan because it's greater than 7. So the final operation required in order to get the rest of the markup that I need for my summary table is to render the rest of the table cells with my tdClassRenderer. Now if you remember, that template expects to have an object that has className and value in it. So, by adding className into it, it'll have everything it needs in order to render that template. So back to the script file, you can see once I have the monthlySummary I pass in compile template, which is the tdWithClassRenderer. Once I have that markup, then I can inject it in to the tbody element of my table. And so that places it right here, where you see the comment for td-class-name-template.
ViewModel: Render Properties
The next order of business is to render the properties out on the page. So, I'll right-click here and I'll go to definition. So this function accepts either the collection of properties that I'm working with, and this argument comes into play when the data's been filtered and I want to render these properties out on the page, but it's not all the properties. It's just the filtered set of them. So here I have an opportunity to use isUndefined for my properties argument. So if nothing's passed in to this function, I'll go to my data module and get all properties. Then I can render the template by passing in the properties and the propertiesRenderer. Now the propertiesRenderer is the compile template for my properties. So, let's take a look at the markup for that template. Starting up here I have my script tag for "properties-list-template" and again remember, I'm setting the type to "text/template" so the browser skips all this, but I can still work with it like it's regular HTML. And also if you remember from the beginning, I'm using Bootstrap to handle some of the layout concerns so I'm using the layout grid here in order to set up a fluid row. The first cell in my row with span 2 cell lengths and offset it by 1. Then I create an image, an object that will be coming into this template will have an imageURL property on it. And if you recall, that's the value that will come from that custom keyword that I created from mockJSON. Then the streeAddress, city, state, and zip. The county and as I scroll down here, the number of bedrooms, bathrooms, squarefeet, and description. So that will be generated for each one of the properties that's fed into the template. And the final markup will be injected in here to this div with the id of "properties-list". So once I have all the markup generated for my list of properties, then I can inject it in to the propertiesList div and this variable here points to the div element that I showed you underneath the template. And then when I'm going back from filtering and clearing the filter, sometimes the scroll position isn't the right place. So, I'm using jQuery to scroll to the top of that div. And then I also have an element that displays the number of properties that's in the current collection. So here I can use the Underscore size function to report out the number of properties that happen to be in the current list.
ViewModel: City, County and Quick Facts
Now to finish off rendering what's left of the UI, the function will render out the counties, cities, and the quickFacts. So, in order to the counties I just need to go to my data module and from the properties get the counties. Once I have those I can use Underscore to iterate over each one and append an option in to the selection list that I set aside as countyList. And I can do the very same thing for the cityList. Finally, for the quickFacts, I have an object here that has a property for the highest price, the lowest price, and the average. Here I'm using my mixin to format my number to show the numberWithCommas for each one of those values. Once the quickFacts objects is fully prepared, then I can use my renderer to render it against the quickFacts template, which I compiled under the quickFactsRenderer. Let's take a look at that really quick. The template for the quickFacts is right here. Again, a script tag with a type of "text/template" and then I have some really simple markup here. It's accepting high, low, and average, which is exactly what the object has that I'm passing in to the renderer. The markup from that template will be injected into this container here for the "quick-facts-container". Again, the comment shows you exactly where it'll be placed. So once the markup is generated for the quickFacts then I can inject it in to the "quick-facts-container" and then at that point all the information that needs to be rendered, is rendered onto the page.
ViewModel: Process Elements
The next thing the init function does is runs the processElements function. And the whole purpose of processElements is basically just to attach things to the DOM and get elements set up for interaction and styling. So here, I'm selecting all the tables in the markup, adding the Bootstrap 'table' class, as well as the Bootstrap 'table-bordered' class. Then if you remember from my properties list I have some links here for Map and More Info. They don't do anything so, in case you click on it, I just wanted to show this message here for Sorry, not implemented. So using the on function allows me to do that, even when the properties are filtered and reset back to the original list. Then I add click handlers for each of my buttons, filter, click, send-to-marketing, and send-to-manager. And I'll go over each of those functions in just a moment. Then lastly, I have some elements on my page, which I've marked with the defer CSS class. Originally, those items are hidden in the browser using display none and then I use jQuery to fade them in. It just gives it a nice look. This way the page shows the logo and some of the design elements first, but then as all that processing and all of the gluing together of the UI elements is being done, it will finally fade in once everything is ready and available to show the user.
ViewModel: Filter and Clear Filter
Now filtering the list gives me a chance to use the Underscore's where function in order to filter out only the properties that I want based off of the criteria that comes in from the user. Now, that's all wrapped up by the filterBy function, but what I need to do is make sure that I'm passing in an object that represents the filter that I want. So here within the filterList function, I'm declaring a few variables here for properties and filter. So first, I'm looking at the countyList and if the 'selectedIndex' does not equal 0, then I can extract the value out of that list and create a property on my filter object for county. Then I can also take a look at the cityList. Again, if there's a selection there grab that value and create a property on my filter for city. Now I'm looking to see if filter does not equal an empty object. So basically, do I have some data that's coming from the user to filter on? If that evaluates to false, then I can pass my filter object down in to filterBy and the return value will be the filtered list of properties. Once I have those properties, I can pass them in to renderProperties and the UI is updated with only the filtered list of properties. With clearFilter I'm calling renderProperties with no arguments. So, if you recall that will go and grab all of the properties and render them out onto the page. And then I'm just resetting my select list here by setting the 'selectedIndex' to 0 on my county and cityList.
ViewModel: Send to Buttons
The last bit of logic to implement in the sale summary is the implementation for the Send To Marketing and Send To Manager buttons. Now Marketing wants to know about the properties that have been sold this year from this report, but it doesn't need all the data that's found within this report. So here, I'm getting all the properties and then running a map on it so that the final result of this operation will be a new array of objects, but before I do that, I want to omit out a number of the elements from those objects. So, they don't need the description, squarefeet, imageURL certainly. They don't need the county, bedrooms or bathrooms. But everything else within that property object, they want that information. So I can call Underscore's omit in order to trim down the data that's found within that object. Now, I'm not actually sending it anywhere here, but you can see how I'm using omit and map together in order to create a filtered list of the data to send it off to some other destination. sendToManager does a similar thing. Here I'm calling map against all the properties, except the Managers only need to know about the property ID and the associated price. So here, instead of omitting everything, I'm calling pick just to grab the ones that I want. And again, once I have that result I can send it off somewhere, an AJAX service, web service, whatever's necessary for your application.
Summary
Well there you have it. During our time together, we've had an opportunity to get acquainted with each function in the Underscore library and see how they can be used conceptually, as well as practically in a close to real-world scenario. This is Craig Shoemaker and I want to say thanks for joining me for this course and I wish you all the best in your development endeavors. If you like what youv'e seen here please join me for some of my other Pluralsight Courses. If you'd like to learn more about HTML5, I suggest you checkout HTML5 Fundamentals and Advanced Courses. If building Windows 8 applications and JavaScript interest you, you can check out my course on that as well. Thanks again.
Course author
Craig Shoemaker
Craig Shoemaker is a developer, instructor, writer, podcaster, and technical evangelist of all things awesome.
Course info
LevelIntermediate
Rating
(294)
My rating
Duration2h 55m
Released8 May 2013
Share course