The underscore encapsulates common JavaScript object manipulation methods for improved development efficiency. (underscore can also be used in the node. JS Runtime environment.) )
Before you learn underscore, you should save its API address, because you will often visit it later:
Http://documentcloud.github.com/underscore/
As you can see from the API, underscore does not have any complex structures and processes, it simply provides a series of commonly used functions. If you use the method from the API to the beginning, you will know it very well.
Nevertheless, I think it is necessary to take some important approaches to discuss with you, they are very important, but in the API is not clear enough to describe.
5.1 Underscore object Encapsulation
Underscore does not extend in the native JavaScript object prototype, but, like jquery, encapsulates the data in a custom object (hereinafter referred to as "underscore object").
You can get native JavaScript data by invoking the value () method of a underscore object, for example:
JS Code
- Defining a JavaScript built-in object
- var jsdata = {
- Name: ' data '
- }
- Create an object as a underscore object with the _ () method
- The prototype of the Underscoredata object contains all the methods defined in the underscore, which you can use arbitrarily
- var Underscoredata = _ (Jsdata);
- The raw data is obtained through the value method, i.e. Jsdata
- Underscoredata.value ();
5.2 Priority calls to JavaScript 1.6 built-in methods
There are many methods in underscore that have been incorporated into the specification in JavaScript1.6, so the built-in methods provided by the hosting environment are prioritized within the underscore object (if the hosting environment has already implemented these methods), thereby increasing the efficiency of the function execution.
For host environments that do not support JavaScript 1.6, underscore is implemented in its own way, which is completely transparent to developers.
The hosting environment described here may be the node. JS runtime Environment, or the client browser.
5.3 Changing the namespace
Underscore uses _ (underscore) to access and create objects by default, but the name may not conform to our naming conventions or cause naming conflicts.
We can use the Noconflict () method to change the name of the underscore and restore the value before the _ (underscore) variable, for example:
JS Code
- <script type="Text/javascript" >
- var _ = ' Custom variable ';
- </script>
- <script type="Text/javascript" src="underscore/underscore-min.js" ></script>
- <script type="Text/javascript" >
- //Underscore object
- Console.dir (_);
- //Rename the underscore object to us, followed by us to access and create the underscore object
- var us = _.noconflict ();
- //output "Custom variable"
- Console.dir (_);
- </script>
5.4 Chain operation
Remember how we did the linking operation in jquery? For example:
JS Code
- $ (' a ')
- . css (' position ', ' relative ')
- . attr (' href ', ' # ')
- . Show ();
Underscore also supports chained operations, but you need to call the chain () method first to declare it:
JS Code
- var arr = [10, 20, 30];
- _ (ARR)
- . Chain ()
- . Map (function (item) { return item++;})
- . First ()
- . value ();
If the chain () method is called, underscore wraps the called method inside a closure and encapsulates the return value as a underscore object and returns:
JS Code
- This is a key function in underscore that implements chained operations, encapsulates the return value as a new underscore object, and calls the chain () method again, providing support for the next function in the method chain.
- var result = function (obj, chain) {
- return chain _ (obj). Chain (): obj;
- }
5.5 Extension Underscore
We can easily extend the custom method to underscore with the mixin () method, for example:
JS Code
- _.mixin ({
- Method1: function (object) {
- //Todo
- },
- METHOD2: function (arr) {
- //Todo
- },
- METHOD3: function (fn) {
- //Todo
- }
- });
These methods are appended to the underscore prototype object, and all created underscore objects can use these methods, and they enjoy the same environment as other methods.
5.6 Iterating through the collection
The each () and map () methods are the two most commonly used methods used to iterate over a collection (an array or an object) and sequentially process each element in the collection, for example:
JS Code
- var arr = [1, 2, 3];
- _ (ARR). Map (function (item, i) {
- Arr[i] = Item + 1;
- });
- var obj = {
- First:1,
- Second:2
- }
- _ (obj). each (function (value, key) {
- return Obj[key] = value + 1;
- });
The map () method has the same function as the each () method, but it records the result returned by each iteration function to a new array and returns.
5.7 Function throttling
function throttling is the control of a function's execution frequency or interval (just like the gate that controls the flow of water), underscore provides the debounce () and throttle () Two methods for function throttling.
To describe these two methods more clearly, let's say we need to implement two requirements:
Requirement 1: When the user enters search criteria in the text box, automatically queries the matching keywords and prompts the user (as if entering search keywords in Tmall)
First, we analyze the 1th requirement, we can bind the KeyPress event of the text box, and when the input box contents change, the query matches the keyword and shows. Let's say I want to query "Windows Phone", which contains 13 characters, and I'm typing it takes only 1 seconds (as if it's a bit fast, meaning it), then in these 1 seconds, 13 query methods are called. This is a very scary thing, and if Tmall is done this way, I'm afraid it will hang up before Singles Day arrives (of course, it's not so fragile, but it's definitely not the best solution)
A better way is if we want the user to have entered the completion, or are waiting for a prompt (perhaps he is too lazy to input the following), then query the matching keyword.
Finally we found that in both cases we expected the user to temporarily stop the input, so we decided to wait for the user to pause the input for 200 milliseconds before the query (if the user is constantly entering the content, then we think he may be very clear about the keyword he wants, so we will prompt him again)
At this point, using the Debounce () function in underscore, we can easily implement this requirement:
JS Code
- <input type="text" id="search" name="search"/>
- <script type="Text/javascript" >
- var query = _ (function () {
- //query operation here
- }). debounce (200);
- $ (' #search '). Bind (' keypress ', query);
- </script>
As you can see, our code is very concise, throttling control has been implemented in the Debounce () method, and we only tell it that when the query function has not been called within 200 milliseconds, it executes our query operation and then binds the query function to the KeyPress event of the input box.
How does the query function come from? When we call the Debounce () method, we pass a function that executes the query and a time (in milliseconds), and the Debounce () method throttles the function based on the time we passed and returns a new function (that is, the query function). We can safely invoke the query function, and the Debounce () method will help us to control it as required.
Requirement 2: Call the server interface to check for new content when the user drags the browser scroll bar
To analyze the 2nd requirement, we can bind the query method to the Window.onscroll event, but this is obviously not a good practice, because a user dragging a scroll bar can trigger dozens of or even hundreds of onscroll events.
Can we use the Debounce () method above for throttling control? When the user has finished dragging the scroll bar, then query the new content? But this does not match the requirements, and the user wants to see changes in the new content as they drag.
So we decided to do this: when the user drags, the interval of every two queries is not less than 500 milliseconds, and if the user drags for 1 seconds, this may trigger 200 onscroll events, but we only make 2 queries at most.
Using the throttle () method in underscore, we can also easily implement this requirement:
JS Code
- <script type="Text/javascript" >
- var query = _ (function () {
- //query operation here
- }). Throttle (500);
- $ (window). Bind (' scroll ', query);
- </script>
The code is still very concise, because within the throttle () method, all the controls that have been implemented for us.
You may have found that the debounce () and throttle () Two methods are very similar (including invocation and return values), but have different effects.
They are used for function throttling, and control functions are not frequently called, saving both client and server resources.
- The Debounce () method focuses on the interval of function execution, where the call time of a function two times cannot be less than the specified time.
- The throttle () method pays more attention to the execution frequency of the function, that is, the function is called only once within the specified frequency.
5.8 Template parsing
Underscore provides a lightweight template parsing function that helps us effectively organize page structure and logic.
I will introduce it through an example:
JS Code
- <!--to display the rendered label--
- <ul id="element" ></ul>
- <!--define templates to place template content in a script tag--
- <script type="text/template" id="TPL" >
- <% for (var i = 0; i < list.length; i++) {%>
- <% var item = list[i]%>
- <li>
- <span><%=item.firstName%> <%=item.lastName%></span>
- <span><%-item.city%></span>
- </li>
- <%}%>
- </script>
- <script type="Text/javascript" src="underscore/underscore-min.js" ></script>
- <script type="Text/javascript" >
- //Get render elements and template content
- var element = $ (' #element '),
- TPL = $ (' #tpl '). html ();
- //Create data that you may have obtained from the server
- var data = {
- List: [
- {firstName: ' <a href= ' # ' >Zhang</a> ', lastName: ' San ', City: ' Shanghai '},
- {firstName: ' Li ', lastName: ' Si ', City: ' <a href= ' # ' >Beijing</a> '},
- {firstName: ' Wang ', lastName: ' Wu ', City: ' Guangzhou '},
- {firstName: ' Zhao ', lastName: ' Liu ', City: ' Shenzhen '}
- ]
- }
- //Parse template, return parsed content
- var html = _.template (TPL, data);
- //Populate the parsed content with the rendered element
- element.html (HTML);
- </script>
In this example, we put the template content in a <script> tag, and you may have noticed that the type of the label is text/template rather than text/javascript because it cannot be run directly as a JavaScript script.
I also recommend that you put the template content in <script>, because if you write them in a <div> or other tag, they may be added to the DOM tree for parsing (even if you hide the tag).
_.template template functions can only parse 3 template labels (this is much simpler than smarty, JSTL):
<%%>: Used to contain JavaScript code that will be executed when the data is rendered.
<%=%>: For output data, it can be a variable, a property of an object, or a function call (the return value of the output function).
<%-%>: Used to output data while converting HTML characters contained in the data into solid form (for example, it converts double quotes to ") to avoid XSS attacks.
<%-%> tags are often used when we want to display the HTML in the data as text.
Underscore also allows you to modify the form of these 3 tags, if we want to use {%}, {%=%}, {%-%} as tags, can be implemented by modifying the templatesettings, like this:
JS Code
- _.templatesettings = {
- Evaluate:/\{% ([\s\s]+?) \%\}/g,
- Interpolate:/\{%= ([\s\s]+?) \%\}/g,
- Escape:/\{%-([\s\s]+?)%\} /g
- }
In this example, we pass the template content and the data that needs to be populated to the template method, which is processed in the following order:
- Parsing template content into executable JavaScript (parsing template tags)
- Using the WITH statement to modify the parsed JavaScript scope to the data object we passed, which allows us to access the properties of the data object directly in the template through variable form
- Perform parsed JavaScript (populate the template with data)
- Returns the result after execution
We often encounter a situation where multiple calls to the template method render data to the same template.
Let's say we have a paging list where each piece of data is rendered through a template, and when the user goes to the next page, we get the next page of data and re-render it, and actually the template is the same each time it is rendered, but all the processing of the templates just described is always executed.
In fact, the underscore template method provides a more efficient way to call, we change the last two sentences in the above code to:
JS Code
- Parse the template and return the parsed content
- var render = _.template (TPL);
- var html = render (data);
- Populate the rendered element with parsed content
- element.html (HTML);
You will find subtle differences: When we call the template method, we pass only the content of the templates, and we do not pass the data, and the template method parses the contents of the templates, generates the parsed executable JavaScript code, and returns a function. The function body is the parsed JavaScript, so when we call the function to render the data, we omit the template parsing action.
You should store the returned function (as if I were storing it in a render variable), and then render the data by invoking the function, especially if the same template might be rendered more than once, which would improve the efficiency of execution (how much more, depending on the length and complexity of your template, But anyway, it's a good habit.