精品学习网->精美文摘

上一篇    全部文章
Underscore.js-精巧而强大实用功能库

Underscore.js-精巧而强大实用功能库


前言

从其他语言转向Javascript时,通常都会遇到一些困惑性问题。比如,Java中的HashMap在Javascript中如何实现?Javascript面向对象式编程如何实现继承?如何实现通用的iterator对集合对象做遍历?如何对Array实现快速排序?….

如果你真的可以自己实现这些功能,那么你的Javascript基础很扎实的!我很佩服你!但对于大部分人来说,这些基础功能应该是由底层API支持的,就像JDK一样。Underscore为我们提供了这样的一个实用工具包,而且它真的很实用!


目录

Underscore介绍
Underscore安装
集合部分:数组或对象
数组部分
函数部分
对象部分
实用功能
链式语法
字符串处理Underscore.String

1. Underscore介绍

Underscore 是一个JavaScript实用库,提供了类似Prototype.js的一些功能,但是没有继承任何JavaScript内置对象。它弥补了部分jQuery没有实现的功能,同时又是Backbone.js必不可少的部分。 Underscore提供了80多个函数,包括常用的: map, select, invoke — 当然还有更多专业的辅助函数,如:函数绑定, JavaScript模板功能, 强类型相等测试, 等等. 在新的浏览器中, 有许多函数如果浏览器本身直接支持,将会采用原生的,如 forEach, map, reduce, filter, every, some 和 indexOf. Underscore介绍来自官方文档,Underscore.js (1.7.0) 中文API文档:http://www.css88.com/doc/underscore/

2. Underscore安装

Underscore.js是一个Javascript功能类库,不依赖于环境,可以加载到HTML中在浏览器运行,也可以直接在nodejs的环境中使用。 为了方便介绍函数功能,我这里选择在nodejs的环境中运行。 我的系统环境 js 代码: win7 64bit, node v0.10.5, npm 1.2.19 安装Underscore js 代码: ~ D:\workspace\javascript>mkdir nodejs-underscore ~ D:\workspace\javascript>cd nodejs-underscore ~ D:\workspace\javascript\nodejs-underscore>npm install underscore npm http GET https://registry.npmjs.org/underscore npm http 304 https://registry.npmjs.org/underscore npm http GET https://registry.npmjs.org/underscore/-/underscore-1.5.1.tgz npm http 200 https://registry.npmjs.org/underscore/-/underscore-1.5.1.tgz underscore@1.5.1 node_modules\underscore underscore有80多的函数,下面我只介绍一些,我比较感兴趣的,实用的。

3. 集合部分: 数组或对象

新建一个collection.js文件,测试underscore对集合的支持。 js 代码: ~ vi collection.js //加载underscore库 var _ = require("underscore")._; each: 对集合循环操作 js 代码: _.each([1, 2, 3], function (ele, idx) { console.log(idx + ":" + ele); }); => 0:1 1:2 2:3 map: 对集合以map方式遍历,产生一个新数组 js 代码: console.log( _.map([1, 2, 3], function(num){ return num * 3; }) ); => [3, 6, 9] reduce: 集合元素合并集的到memo js 代码: console.log( _.reduce([1, 2, 3], function (memo, num) { return memo + num; }, 0) ); => 6 filter: 过滤集合中符合条件的元素。注:find:只返回第一个 js 代码: console.log( _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }) ); => [ 2, 4, 6 ] reject: 过滤集合中不符合条件的元素 js 代码: console.log( _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }) ); => [ 1, 3, 5 ] where: 遍历list, 返回新的对象数组 js 代码: var list = [ {title:"AAA",year: 1982}, {title:"BBB",year: 1900}, {title:"CCC",year: 1982} ]; console.log( _.where(list,{year: 1982}) ); => [ { title: 'AAA', year: 1982 }, { title: 'CCC', year: 1982 } ] contains:判断元素是否在list中 js 代码: console.log( _.contains([1, 2, 3], 3) ); invoke:通过函数名调用函数运行 js 代码: console.log( _.invoke([[5, 1, 7]], 'sort') ); => [ [ 1, 5, 7 ] ] pluck: 提取一个集合里指定的属性值 js 代码: var users = [ {name: 'moe', age: 40}, {name: 'larry', age: 50} ]; console.log( _.pluck(users, 'name') ); => [ 'moe', 'larry' ] max,min,sortBy: 取list中的最大,最小元素,自定义比较器 js 代码: console.log( _.max(users, function (stooge) { return stooge.age; }) ); => { name: 'larry', age: 50 } var numbers = [10, 5, 100, 2, 1000]; console.log( _.min(numbers) ); => 2 console.log( _.sortBy([3, 4, 2, 1 , 6], function (num) { return Math.max(num); }) ); => [ 1, 2, 3, 4, 6 ] groupBy: 把一个集合分组成多个集合 js 代码: console.log( _.groupBy(['one', 'two', 'three'], 'length') ); => { '3': [ 'one', 'two' ], '5': [ 'three' ] } countBy: 把一个数据分组后计数 js 代码: onsole.log( _.countBy([1, 2, 3, 4, 5], function (num) { return num % 2 == 0 ? 'even' : 'odd'; }) ); => { odd: 3, even: 2 } shuffle: 随机打乱一个数据 js 代码: console.log( _.shuffle([1, 2, 3, 4, 5, 6]) ); => [ 1, 5, 2, 3, 6, 4 ] toArray: 将list转换成一个数组 js 代码: console.log( (function () { return _.toArray(arguments).slice(1); })(1, 2, 3, 4) ); => [ 2, 3, 4 ] size: 得到list中元素个数 js 代码: console.log( _.size({one: 1, two: 2, three: 3}) );

4. 数组部分

新建一个array.js js 代码: ~ vi array.js var _ = require("underscore")._; first,last,initial,rest: 数组的元素操作。 js 代码: var nums = [5, 4, 3, 2, 1]; console.log(_.first(nums)); console.log(_.last(nums)); console.log(_.initial(nums,1)); console.log(_.rest(nums,1)); => 5 1 [ 5, 4, 3, 2 ] [ 4, 3, 2, 1 ] indexOf,lastIndexOf,sortedIndex:取索引位置 js 代码: console.log(_.indexOf([4, 2, 3, 4, 2], 4)); console.log(_.lastIndexOf([4, 2, 3, 4, 2], 4)); console.log(_.sortedIndex([10, 20, 30, 40, 50], 35)); => 0 3 3 range: 创建一个范围整数数组 js 代码: console.log(_.range(1,10)); console.log(_.range(0, -10, -1)); => [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] [ 0, -1, -2, -3, -4, -5, -6, -7, -8, -9 ] compact:数组去除空值 js 代码: console.log( _.compact([0, 1, false, 2, '', 3]) ); => [ 1, 2, 3 ] flatten:将一个嵌套多层的数组(嵌套可以是任何层数)转换为只有一层的数组 js 代码: console.log( _.flatten([1, [2], [3, [[4]]]]) ); => [ 1, 2, 3, 4 ] without: 去掉元素 js 代码: console.log( _.without([1, 2, 1, 0, 3, 1, 4], 0,1 ) ); => [ 2, 3, 4 ] union,intersection,difference,uniq: 并集,交集,差集,取唯一 js 代码: console.log(_.union([1, 2, 3], [101, 2, 1, 10], [2, 1])); console.log(_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1])); console.log(_.difference([1, 2, 3, 4, 5], [5, 2, 10])); console.log(_.uniq([1, 2, 1, 3, 1, 2])); => [ 1, 2, 3, 101, 10 ] [ 1, 2 ] [ 1, 3, 4 ] [ 1, 2, 3 ] zip: 合并多个数组中的元素,是group的反向操作 js 代码: console.log( _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]) ); => [ [ 'moe', 30, true ], [ 'larry', 40, false ], [ 'curly', 50, false ] ] object: 把数组转换成对象 js 代码: console.log( _.object(['moe', 'larry', 'curly'], [30, 40, 50]) ); => { moe: 30, larry: 40, curly: 50 }

5. 函数部分

新建一个function.js js 代码: ~ vi function.js var _ = require("underscore")._; bind: 绑定函数到对象上, 无论何时函数被调用, 函数里的this都指向对象. js 代码: var func = function(greeting){ return greeting + ': ' + this.name }; func = _.bind(func, {name : 'moe'}, 'hi'); console.log(func()); => hi: moe bindAll: 绑定方法名到对象上, 当这些方法被执行时将在对象的上下文执行. 绑定函数用作事件处理时非常方便, 否则函数调用时 this 关键字根本没什么用. js 代码: var buttonView = { label : 'underscore', onClick : function(){ console.log('clicked: ' + this.label); }, onHover : function(){ console.log('hovering: ' + this.label); } }; var func = _.bindAll(buttonView, 'onClick', 'onHover'); func.onClick(); => clicked: underscore partial:在不改变this的情况下,通过参数填充数据 js 代码: var add = function(a, b) { return a + b; }; add5 = _.partial(add, 5); console.log(add5(10)); => 15 memoize: 通过缓存计算结果使函数具有记忆功能。 js 代码: var fibonacci = _.memoize(function(n) { return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); }); console.log(fibonacci(10)); => 55 delay: 在等待xx毫秒之后调用函数,类似于setTimeout js 代码: var log = _.bind(console.log, console); _.delay(log, 1000, 'sleep 1s'); => sleep 1s defer: 延迟调用函数, 直到当前调用栈被清空为止, 跟使用 setTimeout 赋予0毫秒的延时很像. 对执行高消耗算法或大型HTML呈现而不阻碍UI更新线程很有用. js 代码: _.defer(function(){ console.log('deferred'); }); => deferred throttle:返回一个类似于节流阀一样的函数, 当高频率的调用函数, 实际上会每隔 wait 毫秒才会调用一次. 对于高到您感觉不到的高频率执行的函数时非常有用. js 代码: var throttled = _.throttle(function(){ _(5).times(function(n){ console.log(n+":"+new Date()); }); }, 100); throttled(); => 0:Wed Aug 28 2013 14:20:48 GMT+0800 1:Wed Aug 28 2013 14:20:48 GMT+0800 2:Wed Aug 28 2013 14:20:48 GMT+0800 3:Wed Aug 28 2013 14:20:48 GMT+0800 4:Wed Aug 28 2013 14:20:48 GMT+0800 debounce: 返回函数的防反跳版本, 将延迟函数的执行(真正的执行)在函数最后一次调用时刻的等待xx毫秒之后,可以实现延迟加载。 js 代码: var lazyLoad = _.debounce(function(){ console.log("lazy load 3s"); }, 3000); lazyLoad(); => lazy load 3s once: 创建一个只能运行一次的函数. 重复调用此修改过的函数会没有效果, 只会返回第一次执行时返回的结果。单例模式。 js 代码: var initialize = _.once(function(){console.log('initialize');}); initialize(); initialize(); => initialize after: 对循环计数,只有超过计数,才会调用指定的函数 js 代码: var nums = [1,2,3,4]; var renderNums = _.after(nums.length, function(){ console.log('render nums'); }); _.each(nums, function(num) { console.log('each:'+num); renderNums(); }); => each:1 each:2 each:3 each:4 render nums wrap: 以函数作为函数传递,可以增加函数调用前后的控制。有点类似于 “模板方法模式” js 代码: var hello = function(name) { return "hello: " + name; }; hello = _.wrap(hello, function(func) { return "before, " + func("moe") + ", after"; }); console.log(hello()); => before, hello: moe, after compose: 组合函数调用关系,把单独的f(),g(),h()组合成f(g(h())) js 代码: var greet = function(name){ return "A: " + name; }; var exclaim = function(statement){ return "B: "+statement + "!"; }; var welcome = _.compose(exclaim, greet); console.log(welcome('moe')); => B: A: moe!

6. 对象部分

新建一个object.js js 代码: ~ vi object.js var _ = require("underscore")._; keys,values,paris,invert: 取属性名,取属性值,把对象转换成[key,value]数组,对调键值 js 代码: var obj = {one: 1, two: 2, three: 3} console.log(_.keys(obj)); console.log(_.values(obj)); console.log(_.pairs(obj)); console.log(_.invert(obj)); => [ 'one', 'two', 'three' ] [ 1, 2, 3 ] [ [ 'one', 1 ], [ 'two', 2 ], [ 'three', 3 ] ] { '1': 'one', '2': 'two', '3': 'three' } functions:返回对象的所有方法名 js 代码: var fun = { fun1:function(){}, fun2:function(){} } console.log(_.functions(fun)); => [ 'fun1', 'fun2' ] extend: 复制对象的所有属性到目标对象上,覆盖已有属性 js 代码: console.log( _.extend({name : 'moe'}, {age : 50}) ); => { name: 'moe', age: 50 } defaults: 复制对象的所有属性到目标对象上,跳过已有属性 js 代码: var iceCream = {flavor : "chocolate"}; console.log( _.defaults(iceCream, {flavor : "vanilla", sprinkles : "lots"}) ); => { flavor: 'chocolate', sprinkles: 'lots' } pick,omit: 返回一个对象的副本,保留指定的属性或去掉指定的属性 js 代码: console.log( _.pick({name : 'moe', age: 50, userid : 'moe1'}, 'name', 'age') ); => { name: 'moe', age: 50 } console.log( _.omit({name : 'moe', age : 50, userid : 'moe1'}, 'userid') ); => { name: 'moe', age: 50 } clone: 引入方式克隆对象,不进行复制 js 代码: console.log( _.clone({name : 'moe'}); ); => {name : 'moe'}; tag: 用对象作为参数来调用函数,作为函数链式调用的一环 js 代码: console.log( _.chain([1,2,3,200]) .filter(function(num) { return num % 2 == 0; }) .tap(console.log) .map(function(num) { return num * num }) .value() ); => [ 2, 200 ] [ 4, 40000 ] has: 判断对象是否包含指定的属性名 js 代码: console.log(_.has({a: 1, b: 2, c: 3}, "b")); isEqual: 判断两个对象是值相等 js 代码: var moe = {name : 'moe', luckyNumbers : [13, 27, 34]}; var clone = {name : 'moe', luckyNumbers : [13, 27, 34]}; console.log(moe == clone); => false console.log(_.isEqual(moe, clone)); => true 判断对象类型的方法,下面反回值都是true js 代码: console.log(_.isEmpty({})); console.log(_.isArray([1,2,3])); console.log(_.isObject({})); console.log((function(){ return _.isArguments(arguments); })(1, 2, 3)); console.log(_.isFunction(console.log)); console.log(_.isString("moe")); console.log(_.isNumber(8.4 * 5)); console.log(_.isFinite(-101)); console.log(_.isBoolean(true)); console.log(_.isDate(new Date())); console.log(_.isNaN(NaN)); console.log(_.isNull(null)); console.log(_.isUndefined(undefined)); => true

7. 实用功能

新建一个util.js js 代码: ~ vi util.js var _ = require("underscore")._; noConflict: 把 “_” 变量的控制权预留给它原有的所有者. 返回一个引用给 Underscore 对象. js 代码: var underscore = _.noConflict(); identity: 返回与传入参数相等的值. 相当于数学里的: f(x) = x js 代码: var moe = {name : 'moe'}; console.log(moe === _.identity(moe)); => true times: 设计调用次数 js 代码: _(3).times(function(n){ console.log(n); }); => 0 1 2 random: 返回范围内的随机数 js 代码: console.log(_.random(0, 100)); => 30 mixin: 封装自己的函数到Underscore对象中,后面Underscore.string就是这种方式的集成 js 代码: _.mixin({ capitalize : function(string) { return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase(); } }); console.log(_("fabio").capitalize()); => Fabio uniqueId:产生一个全局的唯一id,以参数作为前缀 js 代码: console.log(_.uniqueId('contact_')); => contact_1 console.log(_.uniqueId('contact_')); => contact_2 escape,unescape:转义HTML字符串,反转到HTML字符串 js 代码: console.log(_.escape('Curly, Larry & Moe')); => Curly, Larry & Moe console.log(_.unescape('Curly, Larry & Moe')); => Curly, Larry & Moe result: 通过字符串调用对象的函数,或返回属性值 js 代码: var obj = {cheese: 'crumpets', stuff: function(){ return 'nonsense'; }}; console.log(_.result(obj, 'cheese')); => crumpets console.log(_.result(obj, 'stuff')); => nonsense template: 将 JavaScript 模板编译为可以用于页面呈现的函数, 对于通过JSON数据源生成复杂的HTML并呈现出来的操作非常有用. 模板函数可以通过以下两种方式插入到页面中, 使用<%= … %>, 也可以用<% … %>执行任意的 JavaScript 代码. 如果您希望插入一个值, 并让其进行HTML转义, 当您使用创建一个模板时使用 <%- … %> , 传入一个含有与模板对应属性的对象 data. 如果您要写一个一次性的, 您可以传对象 data 作为第二个参数给模板template 来直接呈现, 这样页面会立即呈现而不是返回一个模板函数. 参数 settings 是一个哈希表包含任何可以覆盖的设置 _.templateSettings. js 代码: var compiled = _.template("hello: <%= name %>"); console.log(compiled({name : 'moe'})); =>hello: moe var list = "<% _.each(people, function(name) { %>
  • <%= name %>
  • <% }); %>"; console.log(_.template(list, {people : ['moe', 'curly', 'larry']})); =>
  • moe
  • curly
  • larry
  • var template = _.template("<%- value %>"); console.log(template({value : '').stripTags()); =>a linkalert("hello world!")

         返回顶部
    Underscore.js-精巧而强大实用功能库