In-depth analysis of the role of Backbone. js's dependent library Underscore. js, backboneunderscore
Backbone can be used only when it depends on underscore. js. It must use the functions in underscore to perform basic operations on accessing and processing page elements.
Note: backbone can work well with other js libraries, so it is a library rather than a framework.
Underscore does not extend the native object, but calls the _ () method for encapsulation. Once the encapsulation is complete, the js object becomes the Underscore object. You can also use the Value () of the Underscore object () method to obtain the data in the native js object. (Jquery uses the $ () method to obtain the Jquery object)
Underscore has more than 60 functions. According to different processing objects, it can be divided into five categories: Collection class, array class, function class, object class, and tool function class.
Underscore template () function description:
This function contains three templates:
(1) <%>: contains the logic code, which is not displayed after rendering.
(2) <% = %>: data type. Data is displayed after rendering.
(3) <%-%>: converts HTML tags into common strings to avoid code attacks.
Call format:
_.template(templateString, [data], [setting])
Two-way data binding is not implemented.
1. Underscore object Encapsulation
Underscore is not extended in the native JavaScript Object prototype. Instead, like jQuery, it encapsulates data in a custom object ("Underscore object ").
You can call the value () method of an Underscore object to obtain native JavaScript data, for example:
// Define a JavaScript built-in object var jsData = {name: 'data'} // pass _() method: Create an Underscore object. // the prototype of the underscoreData object contains all the methods defined in Underscore. You can use var underscoreData = _ (jsData) at will ); // obtain the native data through the value method, that is, jsData underscoreData. value ();
2. The JavaScript 1.6 built-in method is preferentially called.
Many methods in Underscore have been incorporated into JavaScript1.6. Therefore, the built-in methods provided by the host environment are preferentially called within the Underscore object (if the host environment has implemented these methods ), to improve the function execution efficiency.
For host environments that do not support JavaScript 1.6, Underscore is implemented in its own way, which is completely transparent to developers.
The host environment mentioned here may be the Node. js runtime environment or the client browser.
3. Change the namespace
By default, Underscore uses _ (underline) to access and create objects. However, this name may not comply with our naming rules or cause naming conflicts.
We can use the noConflict () method to change the name of Underscore and restore the value before the _ (underline) variable, for example:
<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, and use us to access and create the Underscore object var us = _. noConflict (); // output "Custom variable" console. dir (_); </script>
4. Chain Operations
Do you still remember how we perform Link Operations in jQuery? For example:
$('a') .css('position', 'relative') .attr('href', '#') .show();
Underscore also supports chain operations, but you need to call the chain () method to declare it first:
var arr = [10, 20, 30]; _(arr) .chain() .map(function(item){ return item++; }) .first() .value();
If the chain () method is called, Underscore encapsulates the called method in a closure, encapsulates the returned value as an Underscore object, and returns:
// This is the key function for implementing chained operations in Underscore. It encapsulates the returned value into a new Underscore object and calls the chain () method again to support the next function in the method chain. Var result = function (obj, chain) {return chain? _ (Obj). chain (): obj ;}
5. Extended Underscore
We can use the mixin () method to easily extend the custom method to Underscore, for example:
_.mixin({ method1: function(object) { // todo }, method2: function(arr) { // todo }, method3: function(fn) { // todo } });
These methods are appended to the prototype objects of Underscore. All created Underscore objects can use these methods and enjoy the same environment as other methods.
6. traverse the set
The each () and map () methods are the two most commonly used methods. They are used to iterate a set (array or object) and process each element in the Set in sequence. For example:
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 and the each () method have the same functions and parameters, but it records the results returned by each iteration function to a new array and returns it.
7. Function throttling
Function throttling refers to controlling the execution frequency or interval of a function (just like the gate that controls the flow of water). Underscore provides the debounce () and throttle () methods for function throttling.
To describe these two methods more clearly, assume that we need to implement two requirements:
Requirement 1: when a user enters a Search Condition in the text box, the user will automatically query the matched keywords and prompt the user (just like when Tmall enters a search keyword)
First, analyze the 1st requirements. We can bind the keypress event of the text box. When the content of the input box changes, query and display the matching keywords. Suppose I want to query "windows phone", which contains 13 characters, and it takes only 1 second to complete the input (it seems a little fast, that's what it means ), then, 13 query methods are called within the second. This is a terrible thing. If Tmall is implemented in this way, I am worried that it will be suspended before Singles Day (of course, it is not so fragile, but this is definitely not the best solution)
A better way is to query the matching keywords when you want the input to be completed or when you are waiting for a prompt (maybe he is too lazy to enter the following content.
Finally, we found that, in the two situations we expected, the user will temporarily stop inputting, so we decided to pause the user's input for 200 ms before the query (if the user is continuously inputting content, we think he may be very clear about the keyword he wants, so wait and prompt him again)
At this time, using the debounce () function in Underscore, we can easily achieve this requirement:
<Input type = "text" id = "search" name = "search"/> <script type = "text/javascript"> var query = _ (function () {// query here }). debounce (200); $ ('# search '). bind ('keypress ', query); </script>
As you can see, our code is very concise and throttling has been implemented in the debounce () method. We only tell it that the query function has not been called within 200 milliseconds, then, bind the query function to the keypress event in the input box.
How does the query function come from? When we call the debounce () method, we will pass a function that executes the query operation and a time (in milliseconds), debounce () the method will throttle the function based on the time we pass and return a new function (that is, the query function). We can call the query function with confidence, and debounce () the method will help us with control as required.
Requirement 2: When you drag the browser scroll bar, call the server interface to check whether new content exists.
To analyze the 2nd requirements, 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 may trigger dozens or even hundreds of onscroll events.
Can we use the preceding debounce () method for throttling? After dragging the scroll bar, the user can query the new content? However, this is not in line with the requirement, and the user wants to see the changes in the new content during the drag process.
Therefore, we decided to do this: when you drag, the interval between each two queries is not less than 500 milliseconds. If you drag for 1 second, this may trigger 200 onscroll events, however, we can perform a maximum of two queries.
With the throttle () method in Underscore, we can easily achieve this requirement:
<Script type = "text/javascript"> var query = _ (function () {// query here }). throttle (500); $ (window ). bind ('scroll ', query); </script>
The code is still very concise, because in the throttle () method, we have implemented all the control.
You may have discovered that the debounce () and throttle () methods are very similar (including the call method and return value), but they have different functions.
They are all used for function throttling, and control functions are not frequently called, saving client and server resources.
The debounce () method focuses on the interval between function execution. That is, the call time of a function 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.
8. template Parsing
Underscore provides a lightweight template parsing function that helps us effectively organize the Page Structure and logic.
I will introduce it through an example:
<! -- Display the rendered tag --> <ul id = "element"> </ul> <! -- Define a template and place the 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> <%-item. city %> </span> </li> <% }%> </script> <script type = "text/javascript" src = "underscore/underscore-min.js"> </script> <script type = "text/javascript"> // get the rendering element and template content var element =$ ('# element '), tpl = require ('{tpl'{.html (); // create data, which may be the var data you obtained from the server = {list: [{firstName: '<a href = "#"> Zhang </a>', lastName: 'san', city: 'shanghai'}, {firstName: 'lil', lastName: 'si', city: '<a href = "#"> Beijing </a>'}, {firstName: 'wang ', lastName: 'wu', city: 'guangzhou'}, {firstName: 'zhao', lastName: 'liu', city: 'shenzhen '}]} // resolution template, return the parsed content var html = _. template (tpl, data); // fill the parsed content with the rendering element element.html (html); </script>
In this example, we place the template content in a <script> tag. You may have noticed that the type of the tag is text/template rather than text/javascript, because it cannot be directly run 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 this label, it cannot be avoided ).
_. The template function can parse only three template tags (which is much simpler than Smarty and JSTL ):
<%>: Used to include JavaScript code that is executed during data rendering.
<% = %>: Used to output data. It can be a variable, an object attribute, or a function call (Return Value of the output function ).
<%-%>: Used to output data. HTML characters contained in the data are converted to the Entity form (for example, double quotation marks are converted to the "form) to avoid XSS attacks.
When we want to display HTML in the data as text, the <%-%> label is often used.
Underscore also allows you to modify the three tags. If we want to use {%}, {% = %}, {%-%} as tags, you can modify templateSettings, as shown in the following figure:
_.templateSettings = { evaluate : /\{%([\s\S]+?)\%\}/g, interpolate : /\{%=([\s\S]+?)\%\}/g, escape : /\{%-([\s\S]+?)%\}/g }
In this example, the template content and the data to be filled are passed to the template method, which is processed in the following order:
(1) parse the template content into executable JavaScript (parse the template tag)
(2) Use the with statement to change the parsed JavaScript scope to the data object we pass, which enables us to directly access the attributes of the data object in the template in the form of variables.
(3) execute the parsed JavaScript (fill the data in the template)
(4) return the execution result
We often encounter a situation where we call the template method multiple times to render data to the same template.
Suppose we have a paging list. Every piece of data in the list is rendered by a template. When the user enters the next page, we will get the data on the next page and re-render it, in fact, each rendered template is the same, but all the processing processes of the template described above will always be executed.
In fact, the template method of Underscore provides a more efficient calling method. We can modify the last two sentences in the above Code:
// Parse the template and return the parsed content var render = _. template (tpl); var html = render (data); // fill the parsed content with the rendering element element.html (html );
You will find the subtle difference: When we call the template method, we only pass the template content, but not the data, the template method will parse the template content, the parsed JavaScript code is generated and a function is returned. The function body is the parsed JavaScript code. Therefore, when we call this function to render data, this removes the need for template parsing.
You should store the returned function (just as I store it in the render variable), and then call this function to render the data, especially when the same template may be rendered multiple times, this can improve the execution efficiency (the specific increase depends on the length and complexity of your template, but in any case, this is a good habit ).