Underscore简介

 

5. Underscore.js

  Underscore封装了常用的JavaScript对象操作方法,用于提高开发效率。它本身与我们介绍的主题“Backbone”没有半毛钱的关系,因此你可以完全不理会“Backbone”的概念来学习它,或将它单独运用到任何一个页面。(另外,Underscore还可以被使用在Node.js运行环境。)

  在学习Underscore之前,你应该先保存它的API地址,因为你将在以后经常访问它:

  http://documentcloud.github.com/underscore/

  从API中,你已经可以看出,Underscore没有任何复杂的结构和流程,它仅仅提供了一系列常用的函数。如果你将API中的方法从头至尾用一遍,你就会对它非常了解。

  尽管如此,但我觉得还是有必要将一些重要的方法拿出来与大家讨论,它们十分重要,却在API中描述地还不够清楚。

5.1 Underscore对象封装

  Underscore并没有在原生的JavaScript对象原型中进行扩展,而是像jQuery一样,将数据封装在一个自定义对象中(下文中称“Underscore对象”)。

  你可以通过调用一个Underscore对象的value()方法来获取原生的JavaScript数据,例如:

[javascript] view plain copy

  1. // 定义一个JavaScript内置对象  
  2. var jsData = {  
  3.     name : 'data'  
  4. }  
  5.   
  6. // 通过_()方法将对象创建为一个Underscore对象  
  7. // underscoreData对象的原型中包含了Underscore中定义的所有方法,你可以任意使用  
  8. var underscoreData = _(jsData);  
  9.   
  10. // 通过value方法获取原生数据, 即jsData  
  11. underscoreData.value();  

5.2 优先调用JavaScript 1.6内置方法

  Underscore中有许多方法在JavaScript1.6中已经被纳入规范,因此在Underscore对象内部,会优先调用宿主环境提供的内置方法(如果宿主环境已经实现了这些方法),以此提高函数的执行效率。

  而对于不支持JavaScript 1.6的宿主环境,Underscore会通过自己的方式实现,而对开发者来说,这些完全是透明的。

  这里所说的宿主环境,可能是Node.js运行环境,或客户端浏览器。

5.3 改变命名空间

  Underscore默认使用_(下划线)来访问和创建对象,但这个名字可能不符合我们的命名规范,或容易引起命名冲突。

  我们可以通过noConflict()方法来改变Underscore的命名,并恢复_(下划线)变量之前的值,例如:

[html] view plain copy

  1. <script type="text/javascript">  
  2.     var _ = '自定义变量';  
  3. </script>  
  4. <script type="text/javascript" src="underscore/underscore-min.js"></script>  
  5. <script type="text/javascript">  
  6.     // Underscore对象  
  7.     console.dir(_);  
  8.     // 将Underscore对象重命名为us, 后面都通过us来访问和创建Underscore对象  
  9.     var us = _.noConflict();  
  10.     // 输出"自定义变量"  
  11.     console.dir(_);  
  12. </script>  

 

5.4 链式操作

  还记得我们在jQuery中是如何进行链接操作吗?例如:

$('a').css('position', 'relative').attr('href', '#').show();

Underscore同样支持链式操作,但你需要先调用chain()方法进行声明:

[javascript] view plain copy

  1. var arr = [10, 20, 30];  
  2. _(arr)  
  3.     .chain()  
  4.     .map(function(item) {  
  5.         return item++;  
  6.     })  
  7.     .first()  
  8.     .value();  

 如果调用了chain()方法,Underscore会将所调用的方法封装在一个闭包内,并将返回值封装为一个Underscore对象并返回:

[javascript] view plain copy

  1. // 这是Underscore中实现链式操作的关键函数,它将返回值封装为一个新的Underscore对象,并再次调用chain()方法,为方法链中的下一个函数提供支持。  
  2. var result = function(obj, chain) {  
  3.     return chain ? _(obj).chain() : obj;  
  4. }  

5.5 扩展Underscore

  我们可以通过mixin()方法轻松地向Underscore中扩展自定义方法,例如:

[javascript] view plain copy

  1. _.mixin({  
  2.     method1: function(object) {  
  3.         // todo  
  4.     },  
  5.     method2: function(arr) {  
  6.         // todo  
  7.     },  
  8.     method3: function(fn) {  
  9.         // todo  
  10.     }  
  11. });  

这些方法被追加到Underscore的原型对象中,所有创建的Underscore对象都可以使用这些方法,它们享有和其它方法同样的环境。

5.6 遍历集合

  each()和map()方法是最常用用到的两个方法,它们用于迭代一个集合(数组或对象),并依次处理集合中的每一个元素,例如:

[javascript] view plain copy

  1. var arr = [1, 2, 3];  
  2.   
  3. _(arr).map(function(item, i) {  
  4.     arr[i] = item + 1;  
  5. });  
  6.   
  7. var obj = {  
  8.     first: 1,  
  9.     second: 2  
  10. }  
  11.   
  12. _(obj).each(function(value, key) {  
  13.     return obj[key] = value + 1;  
  14. });  

map()方法与each()方法的作用、参数相同,但它会将每次迭代函数返回的结果记录到一个新的数组并返回。

5.7 函数节流

  函数节流是指控制一个函数的执行频率或间隔(就像控制水流的闸门一样),Underscore提供了debounce()和throttle()两个方法用于函数节流。

  为了更清楚地描述这两个方法,假设我们需要实现两个需求:

 

  需求1:当用户在文本框输入搜索条件时,自动查询匹配的关键字并提示给用户(就像在Tmall输入搜索关键字时那样)

  首先分析第1个需求,我们可以绑定文本框的keypress事件,当输入框内容发生变化时,查询匹配关键字并展示。假设我想查询“windows phone”,它包含13个字符,而我输入完成只花了1秒钟(好像有点快,就意思意思吧),那么在这1秒内,调用了13次查询方法。这是一件非常恐怖的事情,如果Tmall也这样实现,我担心它会不会在光棍节到来之前就挂掉了(当然,它并没有这么脆弱,但这绝对不是最好的方案)

  更好的方法是,我们希望用户已经输入完成,或者正在等待提示(也许他懒得再输入后面的内容)的时候,再查询匹配关键字。

  最后我们发现,在我们期望的这两种情况下,用户会暂时停止输入,于是我们决定在用户暂停输入200毫秒后再进行查询(如果用户在不断地输入内容,那么我们认为他可能很明确自己想要的关键字,所以等一等再提示他)

  这时,利用Underscore中的debounce()函数,我们可以轻松实现这个需求:

[html] view plain copy

  1. <input type="text" id="search" name="search" />  
  2. <script type="text/javascript">  
  3.     var query = _(function() {  
  4.         // 在这里进行查询操作  
  5.     }).debounce(200);  
  6.   
  7.     $('#search').bind('keypress', query);  
  8. </script>  

你能看到,我们的代码非常简洁,节流控制在debounce()方法中已经被实现,我们只告诉它当query函数在200毫秒内没有被调用过的话,就执行我们的查询操作,然后再将query函数绑定到输入框的keypress事件。

  query函数是怎么来的?我们在调用debounce()方法时,会传递一个执行查询操作的函数和一个时间(毫秒数),debounce()方法会根据我们传递的时间对函数进行节流控制,并返回一个新的函数(即query函数),我们可以放心大胆地调用query函数,而debounce()方法会按要求帮我们做好控制。

  需求2:当用户拖动浏览器滚动条时,调用服务器接口检查是否有新的内容

  再来分析第2个需求,我们可以将查询方法绑定到window.onscroll事件,但这显然不是一个好的做法,因为用户拖动一次滚动条可能会触发几十次甚至上百次onscroll事件。

  我们是否可以使用上面的debounce()方法来进行节流控制?当用户拖动滚动条完毕后,再查询新的内容?但这与需求不符,用户希望在拖动的过程中也能看到新内容的变化。

  因此我们决定这样做:用户在拖动时,每两次查询的间隔不少于500毫秒,如果用户拖动了1秒钟,这可能会触发200次onscroll事件,但我们最多只进行2次查询。

  利用Underscore中的throttle()方法,我们也可以轻松实现这个需求:

[html] view plain copy

  1. <script type="text/javascript">  
  2.     var query = _(function() {  
  3.         // 在这里进行查询操作  
  4.     }).throttle(500);  
  5.   
  6.     $(window).bind('scroll', query);  
  7. </script>  

代码仍然十分简洁,因为在throttle()方法内部,已经为我们实现的所有控制。

  你可能已经发现,debounce()和throttle()两个方法非常相似(包括调用方式和返回值),作用却又有不同。

  它们都是用于函数节流,控制函数不被频繁地调用,节省客户端及服务器资源。

 

  • debounce()方法关注函数执行的间隔,即函数两次的调用时间不能小于指定时间。
  • throttle()方法更关注函数的执行频率,即在指定频率内函数只会被调用一次。

 

5.8 模板解析

  Underscore提供了一个轻量级的模板解析函数,它可以帮助我们有效地组织页面结构和逻辑。

  我将通过一个例子来介绍它:

[html] view plain copy

  1. <!-- 用于显示渲染后的标签 -->  
  2. <ul id="element"></ul>  
  3.   
  4. <!-- 定义模板,将模板内容放到一个script标签中 -->  
  5. <script type="text/template" id="tpl">  
  6.     <% for(var i = 0; i < list.length; i++) { %>  
  7.         <% var item = list[i] %>  
  8.         <li>  
  9.             <span><%=item.firstName%> <%=item.lastName%></span>  
  10.             <span><%-item.city%></span>  
  11.         </li>  
  12.     <% } %>  
  13. </script>  
  14. <script type="text/javascript" src="underscore/underscore-min.js"></script>  
  15. <script type="text/javascript">  
  16.     // 获取渲染元素和模板内容  
  17.     var element = $('#element'),  
  18.         tpl = $('#tpl').html();  
  19.       
  20.     // 创建数据, 这些数据可能是你从服务器获取的  
  21.     var data = {  
  22.         list: [  
  23.             {firstName: '<a href="#">Zhang</a>', lastName: 'San', city: 'Shanghai'},  
  24.             {firstName: 'Li', lastName: 'Si', city: '<a href="#">Beijing</a>'},  
  25.             {firstName: 'Wang', lastName: 'Wu', city: 'Guangzhou'},  
  26.             {firstName: 'Zhao', lastName: 'Liu', city: 'Shenzhen'}  
  27.         ]  
  28.     }  
  29.       
  30.     // 解析模板, 返回解析后的内容  
  31.     var html = _.template(tpl, data);  
  32.     // 将解析后的内容填充到渲染元素  
  33.     element.html(html);  
  34. </script>  

在本例中,我们将模板内容放到一个<script>标签中,你可能已经注意到标签的type是text/template而不是text/javascript,因为它无法作为JavaScript脚本直接运行。

  我也建议你将模板内容放在<script>中,因为如果你将它们写在一个<div>或其它标签中,它们可能会被添加到DOM树中进行解析(即使你隐藏了这个标签也无法避免)。

  _.template模板函数只能解析3种模板标签(这比Smarty、JSTL要简单得多):

  <%  %>:用于包含JavaScript代码,这些代码将在渲染数据时被执行。

  <%= %>:用于输出数据,可以是一个变量、某个对象的属性、或函数调用(将输出函数的返回值)。

  <%- %>:用于输出数据,同时会将数据中包含的HTML字符转换为实体形式(例如它会将双引号转换为&quot;形式),用于避免XSS攻击。

  当我们希望将数据中的HTML作为文本显示出来时,常常会使用<%- %>标签。

  Underscore还允许你修改这3种标签的形式,如果我们想使用{% %}、{%= %}、{%- %}作为标签,可以通过修改templateSettings来实现,就像这样:

[javascript] view plain copy

  1. _.templateSettings = {  
  2.     evaluate: /\{%([\s\S]+?)\%\}/g,  
  3.     interpolate: /\{%=([\s\S]+?)\%\}/g,  
  4.     escape: /\{%-([\s\S]+?)%\}/g  
  5. }  

在本例中,我们将模板内容和需要填充的数据传递给template方法,它会按以下顺序进行处理:

 

  • 将模板内容解析为可执行的JavaScript(解析模板标签)
  • 通过with语句将解析后的JavaScript作用域修改为我们传递的数据对象,这使我们能够直接在模板中通过变量形式访问数据对象的属性
  • 执行解析后的JavaScript(将数据填充到模板)
  • 返回执行后的结果

 

   我们经常会遇到一种情况:多次调用template方法将数据渲染到同一个模板。

  假设我们有一个分页列表,列表中的每一条数据都通过模板渲染,当用户进入下一页,我们会获取下一页的数据并重新渲染,实际上每次渲染的模板都是同一个,但刚才描述的template所有处理过程总会被执行。

  其实Underscore的template方法提供了一种更高效的调用方式,我们将上面代码中的最后两句修改为:

[javascript] view plain copy

  1. // 解析模板, 返回解析后的内容  
  2. var render = _.template(tpl);  
  3. var html = render(data);  
  4. // 将解析后的内容填充到渲染元素  
  5. element.html(html);  

你会发现细微的差别:我们在调用template方法时只传递了模板内容,而没有传递数据,此时template方法会解析模板内容,生成解析后的可执行JavaScript代码,并返回一个函数,而函数体就是解析后的JavaScript,因此当我们调用该函数渲染数据时,就省去了模板解析的动作。

   你应该将返回的函数存储起来(就像我将它存储在render变量中一样),再通过调用该函数来渲染数据,特别是在同一个模板可能会被多次渲染的情况下,这样做能提高执行效率(具体提升多少,应该根据你的模板长度和复杂度而定,但无论如何,这都是一个良好的习惯)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/456820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

POJ2190 HDU2714 ISBN

USACO 2003 Fall Orange 问题链接&#xff1a;POJ2190 HDU2714 ISBN。 问题简述&#xff1a;参见上述链接。 问题分析&#xff1a; 单纯的计算问题。需要注意以下几点&#xff1a; 1.如果是末尾数&#xff0c;则输出为‘X’&#xff1b; 2.如果能找到对应的值则输出&#xff1b…

Django-安装xadmin的方法及主要配置方法

历经千辛万苦&#xff0c;终于实现了django2.1中xadmin的使用 被论坛里各路神仙带跑N次 准确说是几个小时 直接colne https://github.com/Liu0330/xadmin 工作系统环境&#xff1a;win10Python3.6.xDjango2.1.xXadmin2.0&#xff08;注意2.2版本就不行&#xff01;&#xff…

大数据集群搭建之Linux的安装(一)

1、准备工具 VMWare、centos mimal版本系统文件。 2、工具安装 1、安装vmware软件 安装软件地址&#xff1a; VMWare&#xff1a;http://pan.baidu.com/s/1qYnySrE 密码&#xff1a;3t3r centos mimal版本&#xff1a;http://pan.baidu.com/s/1dE5LY6H 密码&#xff1a…

阻止事件冒泡两种方式:event.stopPropagation();和return false;

jQuery提供了两种方式来阻止事件冒泡。 方式一&#xff1a;event.stopPropagation(); $("#div1").mousedown(function (event) {event.stopPropagation(); }); 方式一&#xff1a;return false; $("#div1").mousedown(function (event) {return false; });…

关于电脑的基础单词笔记

chapter01 mouse 鼠标. keyboard 键盘. notepad 记事本 . sava 保存. chapter02 word 文本文档. office 办公软件. copy 复制. past 粘贴. find 复制. table 表格. page 页. picture 图片. chapter03 sheet 工作薄. cell 单元格. number 数字. true 真. …

Python3.6+Django2.0+Xadmin2.0学生信息管理系统

一、创建模型 模型是表示我们的数据库表或集合类&#xff0c;并且其中所述类的每个属性是表或集合的字段&#xff0c;在 app/models.py 中定义。 1、首先&#xff0c;导入models模块 from django.db import models 接下来创建个学生信息类&#xff0c;其中包含学生姓名、性别…

升级 pip版本

安装第三方库&#xff1a;pip install Pillow 出现 You are using pip version 7.1.2, however version 9.0.1 is available. You should consider upgrading via the python -m pip install --upgrade pip comm and. 解决方法1&#xff1a; 输入“python -m pip install -U pi…

大数据集群搭建之节点的网络配置过程(二)

紧接着上一章来设置windows的vmnet8的ip地址和虚拟机中centos的ip地址。 NAT虚拟网络的配置图如下图所示&#xff1a; 1、这里根据VMware中得到的网关地址去设置vmnet8的ip地址。 网关地址查看&#xff1a; 2、得到的网关地址后去设置vmnet8&#xff0c;将网关地址设置为v…

Python3.6+Django2.0+Xadmin2.0学生信息管理系统-2

1、上传图片/文件等资源 有时候需要添加一些附件&#xff0c;例如&#xff0c;新生刚入学&#xff0c;大家相互之间还不熟悉&#xff0c;希望能通过照片来加深印象&#xff0c;并且方便教学管理。 首先&#xff0c;对demo/urls.py文件进行改造&#xff0c;给urlpatterns添加s…

vim自带的练习教程(vimtutor)

声明&#xff1a;本文源于Centos 7.2系统vim自带的练习教程--vimtutor欢迎阅 读《 V I M 教 程 》 - 版本 1.7 Vim 是一个具有很多命令的功能非常强大的编辑器。限于篇幅&#xff0c;在本教程当中就不详细介绍了。本教程的设计目标是讲述一些必要的基本命令&#xff0c;而掌握…

pycharm之no python interpreter configured for project的解决办法

今天由于重装了系统&#xff0c;所以必须得重新配置一些软件&#xff0c;在打开pycharm运行程序时显示“no python interpreter configured for project”提示。根据字面意思是“python没有解释器”。 解决办法&#xff1a; 找到你之前下载python环境支持库如下图所示&#x…

Python是非常优美的语言,那到底如何个美呢?

我把Python里面非常有名的简洁&#xff0c;高效&#xff0c;方便的代码整理出来&#xff0c;让我们来一睹她的风采。其实每个主题展开讲都是很大的篇幅&#xff0c;今天我们先overview一下 看完之后&#xff0c;相信初学者会更快的喜欢上python. 1.列表推导 要说Python里面最…

js生成验证码并且验证

<html> <head> <title>验证码</title> <style type"text/css"> #code { font-family:Arial; font-style:italic; font-weight:bold; border:0; letter-spacing:2px; color:blue; } </style> <script type &qu…

大数据集群搭建之hadoop、tomcat、jdk等工具的安装(三)

目录一、准备的资源&#xff1a;二、安装配置过程 目录 本章就说下各种软件的安装和配置。 一、准备的资源&#xff1a; 1、tomcat(如用于在网页上查看HDFS的存储等) 地址&#xff1a;http://pan.baidu.com/s/1miC93ny 密码&#xff1a;52dd 2、jdk 地址&#xff1a;ht…

pycharm 快捷键大全

1、编辑&#xff08;Editing&#xff09; Ctrl Space 基本的代码完成&#xff08;类、方法、属性&#xff09; Ctrl Alt Space 快速导入任意类 Ctrl Shift Enter 语句完成 Ctrl P 参数信息&#xff08;在方法中调用参数&#xff09; Ctrl Q 快速查看文档 F1 Web帮…

转载 Spark性能优化指南——基础篇

前言 在大数据计算领域&#xff0c;Spark已经成为了越来越流行、越来越受欢迎的计算平台之一。Spark的功能涵盖了大数据领域的离线批处理、SQL类处理、流式/实时计算、机器学习、图计算等各种不同类型的计算操作&#xff0c;应用范围与前景非常广泛。在美团•大众点评&#xff…

JavaScript 判断变量是否为数组Array的方法

1. 不能用typeof &#xff0c;因为typeof 只能判断基本类型&#xff0c;不能判断引用类型 var ary [1,23,4];console.log(typeof ary); //输出结果是Object上面的办法并不能实时的检测出是否是数组&#xff0c;只能判断其类型&#xff0c;所以说typeof判断基本类型数据还是挺好…

require.js用法简介

一、为什么要用require.js&#xff1f; 最早的时候&#xff0c;所有Javascript代码都写在一个文件里面&#xff0c;只要加载这一个文件就够了。后来&#xff0c;代码越来越多&#xff0c;一个文件不够了&#xff0c;必须分成多个文件&#xff0c;依次加载。下面的网页代码&…

Pycharm新建文件时自动添加基础信息

# -*- coding: utf-8 -*- # Time : ${DATE} ${TIME} # Author : Liu # File : ${NAME}.py 如下图所示 再建一个py文件时就会自动添加信息&#xff1a; # -*- coding: utf-8 -*- # Time : 2019/05/05 11:46 # Author : Liu # File : DOUBAN.py

JTLParser-linux上jmeter的jtl文件二次分析

解析JMeter的JTL文件 2013年01月30日 ⁄ 综合 ⁄ 共 1452字 ⁄ 字号 小 中 大 ⁄ 评论关闭http://code.google.com/p/xtoolkit/wiki/JTLParser Introduction 当把JMeter使用命令行运行后&#xff0c;JMeter会把结果保存到一个指定文件中&#xff08;使用 -l 参数指定&#xff0…