当你细细琢磨一个 JavaScript 库(Underscore.js-1)

Underscore.js

简介

Underscore 是一个 JavaScript 库,在没有拓展任何内置对象的前提下,提供了一整套的函数式编程类型的实用函数。主要解决了这样一个问题:“如果我面对一个空白 HTML 文档,我想要一个高效的编码,该如何开始”。与此同时,她弥补了 jQuery 的不足,也成为 Backbone 的首要依赖。

Underscore 提供了100多个函数,不止包含常用的 map filter invoke 帮你解决日常开发问题,同时提供诸如 函数绑定,视图模板,快速索引,强类型相等测试等等高级功能。

想要进一步研读源码,这里有一份测试代码可以参考。当然更好的方式就是去阅读这份包含注释的源码

尽情享用 Underscore 为你带来的便利。如果你想让这个库更加完美,可以试试Underscore-contrib 本项目源码也托管在 GitHub 上,你可以提交 Issue 来报告 bug 以及参与特性讨论。

Underscore 是 DocumentCloud 的开源组件库。

安装

  • Nodejs npm i underscore
  • Meteor meteor add underscore
  • Require require(['underscore'],...
  • Bower bower i underscore
  • Component component i jashkenas/underscore
  • Yarn yarn add underscore

集合函数

遍历集合 _.each(list, iteratee, [context])

别名 _.forEach

遍历 list 中的所有元素,针对每一个元素可以执行一个 iteratee 函数,如果指定了上下文 context 怎把 iteratee 绑定到这个上下文中。iteratee 指定接收三个参数 (element, index, list) 函数默认返回 list 本身,供链式调用。

_.each([1, 2, 3], alert) // 依次弹出3个值1,2,3
_.each({one: 1, two: 2, three: 3}, alert) // 依次弹出3个值1,2,3

注意 这里的集合包含了数组,对象以及类数组,但应避免传入 Length 属性不确定的集合

有个 each 的抽象版本 _.invoke(list, methodName, *arguments)

这个函数与 each 的区别在于

  • 可以额外传参,参数会在 method 调起时传入,所以对所有元素都会生效
  • 传入的是函数名,而非函数本身

处理集合 _.map(list, iteratee, [context])

别名 _.collect

通过 iteratee 将 list 中的每个值映射到新的数组中, 此方法返回新数组

_.map([1,2,3], (num)=> num*3) // [3, 6, 9]
_.map({one: 1, two: 2, three: 3}, (num, key)=> num*3) //[3,6,9]

有个针对对象数组的精简版本 _pluck(list, propertyName) 用以萃取对象数组中某属性值,返回一个数组。

_.pluck([{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}], 'name');//["moe", "larry", "curly"]

集合降维 _.reduce(list, iteratee, [memo], [context])

别名 _.inject & _.foldl

reduce 将 list 中的元素归结为一个单独的值,memo 是 reduce 的初始值,reduce 每一步都由 iteratee 返回。iteratee 指定接收四个参数,memo, value, index, list。 如果没有传递 memo,reduce 会从第二个元素开始,并将第一个参数作为 memo 传递给处理函数。

sum = _.reduce([1,2,3], (memo, num)=> memo+num) // 6

降维方向如果从集合尾部开始,那么就对应了 _.reduceRight 其实现与 reduce 相同,别名为 _.foldr

let list = [[0, 1], [2, 3], [4, 5]]
let flat = _.reduceRight(list, (pre, next)=> pre.concat(next)); //[4,5,2,3,0,1]

查找定位 _.find(list, predicate, [context])

别名 _.detect

遍历 list 将其中每一个值提供给真值监测函数 predicate。找到匹配的函数立即返回并输出通过检测的元素值,剩余部分无视。

let evenBad = _.find([1,2,3,4,5], (num)=>num%2==0) // 2

排序 _.sortBy(list, iteratee, [context])

返回一个排序后的list拷贝副本。如果传递iteratee参数,iteratee将作为list中每个值的排序依据。迭代器也可以是字符串的属性的名称进行排序的(比如 length)。

_.sortBy([1, 2, 3, 4, 5, 6], (num)=>Math.sin(num)); //[5, 4, 6, 3, 1, 2]

基于查找就有很多事情可以做了。

一、 最值

_.max(list, [iteratee],[context])/ _.min,这两个不仅可以返回数组的最值,还能通过指定比较依据来取得对象数组某个属性的最值。

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.max(stooges, function(stooge){ return stooge.age; });// {name: 'curly', age: 60};

二、索引、分组

_.indexBy(list, iteratee, [context])

用过 Excel 的按行排序吧,这里就是按照 iteratee 指定的元素对 list进行排序。

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.indexBy(stooges, 'age');
=> {
  "40": {name: 'moe', age: 40},
  "50": {name: 'larry', age: 50},
  "60": {name: 'curly', age: 60}
}

_.groupBy(list, iteratee, [context]) 把一个集合分组为多个集合,通过 iterator 返回的结果进行分组. 如果 iterator 是一个字符串而不是函数, 那么将使用 iterator 作为各元素的属性名来对比进行分组.

_.groupBy([1.3, 2.1, 2.4], (num)=>Math.floor(num) });// {1: [1.3], 2: [2.1, 2.4]}

_.groupBy(['one', 'two', 'three'], 'length');//{3: ["one", "two"], 5: ["three"]}

_.countBy(list, iteratee, [context]) 排序一个列表组成一个组,并且返回各组中的对象的数量的计数。类似groupBy,但是不是返回列表的值,而是返回在该组中值的数目。

_.countBy([1, 2, 3, 4, 5], (num)=> num % 2 == 0 ?'even': 'odd';); //{odd: 3, even: 2}

高级查找->全局监测 _.every(list, [predicate], [context])

别名 _.all

如果 list 中 所有对象 都满足 predicate 监测,则返回 true

let isAllOdd = (list)=> _.every(list, (item)=>item%2==0)
isAllOdd([1,2,3,4]) //false

与之相辅的有一个存在性监测, _.some(list, [predicate], [context]) 这种监测类似于 find 但并不返回满足监测的元素,而是 Boolean 值。

别名 _.any

如果 list 中有 任何一个 元素通过 predicate 的真值检测就返回true。一旦找到了符合条件的元素, 就直接中断对list的遍历。

let isHasOdd = (list)=> _.every(list, (item)=>item%2==0)
isHasOdd([1,2,3,4]) //true

存在性监测有个精简版的 _.contains(list, value)

如果 list 中包含 value 的值则返回 true 并终止监测

高级查找->过滤器 _.filter(list, predicate, [context])

别名 _.select

遍历 list 返回包含所有通过predicate真值检测的元素值。

let evenGood = _.filter([1,2,3,4,5], (num)=>num%2==0) //[2,4]

高级查找->使用属性查找对象 _.where(list, properties)

遍历list中的每一个值,返回一个数组,包含了properties所列出的属性的对象集合。

_.where(loves, {name: "meng", year: 1990});// [{id: 1020, name: 'meng', year: '1990}, {id: 1022, name: 'meng', year: '1990}]

如果希望返回的是第一个值,那就可以结合 find 函数的尿性,组成一个 _.findWhere 方法

高级查找->排除法查找 _.reject(list, properties, [context])

返回list中没有通过predicate真值检测的元素集合,与filter相反。

let oddGood = _.reject([1,2,3,4,5], (num)=>num%2==0) //[1,3,5]

乱序函数,舒服了 _.shuffle(list)

返回一个随机乱序的 list 的副本,使用 F-Y 算法实现

_.shuffle([1, 2, 3, 4, 5, 6]); //[4, 1, 6, 3, 5, 2]

随机取样函数 _.sample(list,[n])

从 list中产生一个随机样本。传递一个数字表示从list中返回n个随机元素。否则将返回一个单一的随机项。

_.sample([1, 2, 3, 4, 5, 6]); //4
_.sample([1, 2, 3, 4, 5, 6], 3); //[1, 6, 2]

类数组转换为数组 _.toArray(list)

把list(任何可以迭代的对象)转换成一个数组,在转换 arguments 对象时非常有用。

(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4); // [2,3,4]

集合长度/尺寸 .size(list)

正则分组 _.partition(array, predicate)

拆分一个数组(array)为两个数组:第一个数组其元素都满足predicate迭代函数, 而第二个的所有元素均不能满足predicate迭代函数。

_.partition([0, 1, 2, 3, 4, 5], isOdd);//[[1, 3, 5], [0, 2, 4]]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容