Array有map()和filter()方法,可是Object没有这些方法。此外,低版本的浏览器例如IE6~8也没有这些方法,怎么办?
方法一,自己把这些方法添加到Array.prototype中,然后给Object.prototype也加上mapObject()等类似的方法。
方法二,直接找一个成熟可靠的第三方开源库,使用统一的函数来实现map()、filter()这些操作。
underscore则提供了一套完善的函数式编程的接口,让我们更方便地在JavaScript中实现函数式编程。
jQuery在加载时,会把自身绑定到唯一的全局变量$上,underscore与其类似,会把自身绑定到唯一的全局变量_上,这也是为啥它的名字叫underscore的原因。
Collections
underscore为集合类对象提供了一致的接口。集合类是指Array和Object,暂不支持Map和Set。
| 函数 | 说明 | 代码示例 |
|---|---|---|
| map | 对集合中的每个元素应用给定函数,返回新数组 | _.map([1, 2, 3], x => x * 2); // [2, 4, 6] |
| filter | 根据给定函数测试条件,返回符合条件的新数组 | _.filter([1, 2, 3, 4], x => x > 2); // [3, 4] |
| every | 检查集合是否所有元素都满足给定函数条件 | _.every([1, 2, 3], x => x > 0); // true |
| some | 检查集合是否至少有一个元素满足给定函数条件 | _.some([1, 2, 3], x => x > 2); // true |
| max / min | 分别返回集合中的最大值和最小值 | _.max([1, 2, 3]); // 3 _.min([1, 2, 3]); // 1 |
| groupBy | 根据给定函数对集合进行分组 | _.groupBy([1.3, 2.1, 2.4], x => Math.floor(x)); // { '1': [1.3], '2': [2.1, 2.4] } |
| shuffle / sample | 分别用于打乱集合顺序和随机选择元素 | _.shuffle([1, 2, 3]); _.sample([1, 2, 3], 2); |
Array
underscore为Array提供了许多工具类方法,可以更方便快捷地操作Array。
| 序号 | 函数名 | 说明 | 代码示例 |
|---|---|---|---|
| 1 | first | 取数组的第一个元素 | _.first([2, 4, 6, 8]); // 2 |
| 2 | last | 取数组的最后一个元素 | _.last([2, 4, 6, 8]); // 8 |
| 3 | flatten | 将嵌套数组变成一维数组 | _.flatten([1, [2], [3, [[4], [5]]]]); // [1, 2, 3, 4, 5] |
| 4 | zip | 将多个数组的元素按索引对齐并合并成新数组 | _.zip([‘Adam’, ‘Lisa’, ‘Bart’], [85, 92, 59]); // [[‘Adam’, 85], [‘Lisa’, 92], [‘Bart’, 59]] |
| 5 | unzip | 将由数组组成的数组转换为数组的数组 | _.unzip([[‘Adam’, 85], [‘Lisa’, 92], [‘Bart’, 59]]) // [[‘Adam’, ‘Lisa’, ‘Bart’], [85, 92, 59]] |
| 6 | object | 将两个数组转换为对象,其中第一个数组的元素作为键,第二个数组的元素作为值 | _.object([‘Adam’, ‘Lisa’, ‘Bart’], [85, 92, 59]); // {Adam: 85, Lisa: 92, Bart: 59} |
| 7 | range | 生成一个序列 | _.range(10); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
Functions
因为underscore本来就是为了充分发挥JavaScript的函数式编程特性,所以也提供了大量JavaScript本身没有的高阶函数。
| 函数 | 说明 | 代码示例 |
|---|---|---|
| bind | 绑定函数的this上下文和参数 | _.bind(console.log, console, 'Hello')(); // 'Hello' |
| partial | 创建一个偏函数,固定原函数的某些参数 | _.partial(Math.pow, 2)(5); // 32 |
| memoize | 缓存函数的结果,避免重复计算 | let fib = _.memoize(n => { /* 计算斐波那契数 */ }); |
| once | 确保函数只执行一次 | let greet = _.once(() => console.log('Hello!')); |
| delay | 延迟函数的执行 | _.delay(alert, 1000, 'Hello after 1 second!'); |
Objects
和Array类似,underscore也提供了大量针对Object的函数。
| 函数 | 说明 | 代码示例 |
|---|---|---|
| keys / allKeys | 分别返回对象自身的和包含原型链上的所有键 | _.keys({a: 1, b: 2}); // ['a', 'b'] _.allKeys(xiaoming); |
| values | 返回对象自身的所有值 | _.values({a: 1, b: 2}); // [1, 2] |
| mapObject | 对象的map操作 | _.mapObject({a: 1, b: 2}, (v, k) => v * 2); // { a: 2, b: 4 } |
| invert | 交换对象的键值对 | _.invert({Adam: 90, Lisa: 85}); // { '90': 'Adam', '85': 'Lisa' } |
| extend / extendOwn | 分别用于浅复制和浅复制并忽略原型链的属性 | _.extend({}, {a: 1}, {b: 2}); // {a: 1, b: 2} |
| clone | 浅复制对象 | _.clone({a: 1, b: 2}); // {a: 1, b: 2} |
| isEqual | 深度比较两个对象是否相等 | _.isEqual({a: 1, b: 2}, {a: 1, b: 2}); // true |
Chaining
| 函数 | 说明 | 代码示例 |
|---|---|---|
| chain | 开始一个链式调用 | _.chain([1, 2, 3]).map(x => x * 2).value(); // [2, 4, 6] |
let r = _.chain([1, 4, 9, 16, 25]) .map(Math.sqrt) .filter(x => x % 2 === 1) .value();console.log(r); // [1, 3, 5]