Underscore 是一个 JavaScript 库,它提供了一大堆有用的函数式编程助手,而无需扩展任何内置对象。 它是对以下问题的答案:“如果我坐在一个空白的 HTML 页面前,并希望立即开始高效工作,我需要什么?”…… 以及与 jQuery 的燕尾服和 Backbone 的吊带裤相配的领带。

Underscore 提供了 100 多个函数,支持您最喜欢的日常函数式助手:mapfilterinvoke,以及更专业的工具:函数绑定、JavaScript 模板、创建快速索引、深度相等性测试等等。

包含完整的 测试套件 供您参考。

您也可以通读 带注释的源代码。 还有一个 模块化版本,其中包含可点击的导入引用。

您可以选择整体导入和模块化导入。 下面简要概述了这些选项,并在 文章 中进行了更全面的讨论。

喜欢 Underscore,并希望将其 调到 11? 试试 Underscore-contrib

该项目 托管在 GitHub 上。 您可以在 问题页面 上报告错误和讨论功能,或在 Gitter 频道中聊天。

您可以通过 Patreon 捐款来支持该项目。 企业覆盖范围作为 Tidelift 订阅 的一部分提供。

Underscore 是 DocumentCloud 的一个开源组件。

v1.13.6 下载 (右键单击并使用“另存为”)

65.9 KB,未压缩,包含大量注释  (源代码映射)
8.59 KB,已压缩和 Gzip 压缩  (源代码映射)
68.4 KB,未压缩,包含大量注释  (源代码映射)
7.48 KB,已压缩和 Gzip 压缩  (源代码映射)
未发布,当前master,请您自行判断并承担风险使用
未发布,当前master,如果您感觉幸运的话可以使用

v1.13.6 CDN 地址 (与 <script src="..."></script> 一起使用)

在大多数情况下,您可以将上述版本号替换为latest以便您的嵌入将自动使用最新版本,或者stable如果您希望延迟更新,直到更新被证明没有意外的破坏性更改。 例如
https://cdn.jsdelivr.net/npm/underscore@latest/underscore-umd-min.js

包安装

如果您正在硬编码包中文件的路径,并且不确定要使用哪个构建,则很可能需要underscore-umd.js或压缩版本underscore-umd-min.js.

整体导入(推荐)

模块化导入

对于具有多个别名的函数,模块的文件名始终是文档中出现的第一个名称。 例如,_.reduce/_.inject/_.foldl是从underscore/modules/reduce.js导出的。模块化使用主要推荐用于创建 Underscore 的自定义构建。

引擎兼容性

Underscore 1.x 向后兼容任何完全支持 ES3 的引擎,同时在可用时也利用更新的功能,例如Object.keys、类型化数组和 ES 模块。 我们会定期针对下面列出的 JavaScript 引擎运行单元测试

此外

Underscore 2.x 可能会删除对某些过时环境的支持。

集合函数(数组或对象)

each_.each(list, iteratee, [context]) 别名:forEach 源代码
遍历元素列表,将每个元素依次传递给迭代函数。 如果传递了上下文对象,则迭代函数将绑定到该对象。 每次调用迭代函数时都会传递三个参数(element, index, list)。 如果列表是 JavaScript 对象,则迭代函数的参数将是(value, key, list)。 返回列表以进行链式调用。

_.each([1, 2, 3], alert);
=> alerts each number in turn...
_.each({one: 1, two: 2, three: 3}, alert);
=> alerts each number value in turn...

注意:集合函数适用于数组、对象和类数组对象,例如 arguments, NodeList等。 但它通过鸭子类型工作,因此避免传递具有数字length属性的对象。 还需要注意的是,each循环不能跳出 — 要跳出,请改用 _.find

map_.map(list, iteratee, [context]) 别名:collect 源代码
通过转换函数(迭代函数)映射列表中的每个值来生成一个新的值数组。 迭代函数传递三个参数:value,然后是index(或key)迭代,最后是对整个list.

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

reduce_.reduce(list, iteratee, [memo], [context]) 别名:injectfoldl 源代码
reduce 也称为 injectfoldl,它将值的列表归约为单个值。 Memo 是归约的初始状态,它的每个后续步骤都应由 iteratee 返回。 迭代函数传递四个参数:memo,然后是valueindex(或键)迭代,最后是对整个list.

如果在第一次调用 reduce 时没有传入 memo 参数,迭代函数不会在列表的第一个元素上执行。相反,第一个元素会在迭代函数下次调用时作为 memo 参数传入,并使用列表中的下一个元素。

var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
=> 6

reduceRight_.reduceRight(list, iteratee, [memo], [context]) 别名: foldr 源码
reduce 的右结合版本。Foldr 在 JavaScript 中不像在惰性求值的语言中那样有用。

var list = [[0, 1], [2, 3], [4, 5]];
var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
=> [4, 5, 2, 3, 0, 1]

find_.find(list, predicate, [context]) 别名: detect 源码
遍历 list 中的每个值,返回第一个通过真值测试 (predicate) 的值,或者undefined如果没有值通过测试。该函数一旦找到可接受的元素就会立即返回,并且不会遍历整个列表。predicate 通过 iteratee 进行转换,以便于使用简写语法。

var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> 2

filter_.filter(list, predicate, [context]) 别名: select 源码
遍历 list 中的每个值,返回一个包含所有通过真值测试 (predicate) 的值的数组。predicate 通过 iteratee 进行转换,以便于使用简写语法。

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]

findWhere_.findWhere(list, properties) 源码
遍历 list 并返回与 properties 中列出的所有键值对 匹配第一个 值。

如果未找到匹配项,或者 list 为空,则返回 undefined

_.findWhere(publicServicePulitzers, {newsroom: "The New York Times"});
=> {year: 1918, newsroom: "The New York Times",
  reason: "For its public service in publishing in full so many official reports,
  documents and speeches by European statesmen relating to the progress and
  conduct of the war."}

where_.where(list, properties) 源码
遍历 list 中的每个值,返回一个包含所有与 properties 中列出的键值对 匹配 的值的数组。

_.where(listOfPlays, {author: "Shakespeare", year: 1611});
=> [{title: "Cymbeline", author: "Shakespeare", year: 1611},
    {title: "The Tempest", author: "Shakespeare", year: 1611}]

reject_.reject(list, predicate, [context]) 源码
返回 list 中的值,但不包括通过真值测试 (predicate) 的元素。与 filter 相反。predicate 通过 iteratee 进行转换,以便于使用简写语法。

var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [1, 3, 5]

every_.every(list, [predicate], [context]) 别名: all 源码
如果 list 中的所有值都通过 predicate 真值测试,则返回 true。如果找到一个假元素,则会短路并停止遍历列表。predicate 通过 iteratee 进行转换,以便于使用简写语法。

_.every([2, 4, 5], function(num) { return num % 2 == 0; });
=> false

some_.some(list, [predicate], [context]) 别名: any 源码
如果 list 中的任何值通过 predicate 真值测试,则返回 true。如果找到一个真元素,则会短路并停止遍历列表。predicate 通过 iteratee 进行转换,以便于使用简写语法。

_.some([null, 0, 'yes', false]);
=> true

contains_.contains(list, value, [fromIndex]) 别名: include, includes 源码
如果 value 存在于 list 中,则返回 true。如果 list 是一个数组,则在内部使用 indexOf。使用 fromIndex 从给定索引开始搜索。

_.contains([1, 2, 3], 3);
=> true

invoke_.invoke(list, methodName, *arguments) 源码
list 中的每个值上调用由 methodName 命名的方 法。传递给 invoke 的任何额外参数都将转发到方法调用。

_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
=> [[1, 5, 7], [1, 2, 3]]

pluck_.pluck(list, propertyName) 源码
map 最常见用例的便捷版本:提取属性值列表。

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

max_.max(list, [iteratee], [context]) 源码
返回 list 中的最大值。如果提供了 iteratee 函数,它将用于每个值,以生成对值进行排名的标准。如果 list 为空,则返回 -Infinity,因此可能需要使用 isEmpty 保护。此函数当前只能可靠地比较数字。此函数使用运算符<(注意)。

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};

min_.min(list, [iteratee], [context]) 源码
返回 list 中的最小值。如果提供了 iteratee 函数,它将用于每个值,以生成对值进行排名的标准。如果 list 为空,则返回 Infinity,因此可能需要使用 isEmpty 保护。此函数当前只能可靠地比较数字。此函数使用运算符<(注意)。

var numbers = [10, 5, 100, 2, 1000];
_.min(numbers);
=> 2

sortBy_.sortBy(list, iteratee, [context]) 源码
返回 list 的(稳定)排序副本,按运行每个值通过 iteratee 的结果按升序排列。iteratee 也可以是要排序的属性的字符串名称(例如length)。此函数使用运算符<(注意)。

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

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

groupBy_.groupBy(list, iteratee, [context]) 源码
将集合拆分为多个集合,按运行每个值通过 iteratee 的结果进行分组。如果 iteratee 是字符串而不是函数,则按每个值上由 iteratee 命名的属性进行分组。

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

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

indexBy_.indexBy(list, iteratee, [context]) 源码
给定一个 list 和一个 iteratee 函数(该函数返回列表中每个元素的键或属性名称),返回一个包含每个项目的索引的对象。就像 groupBy 一样,但用于您知道键是唯一的情况。

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}
}

countBy_.countBy(list, iteratee, [context]) 源码
将列表分类为多个组,并返回每个组中对象数量的计数。类似于groupBy,但不是返回一个值列表,而是返回该组中值的计数。

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

shuffle_.shuffle(list) 源码
使用 Fisher-Yates 洗牌算法 的一个版本返回 list 的随机打乱副本。

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

sample_.sample(list, [n]) 源码
list 中生成一个随机样本。传递一个数字以从列表中返回 n 个随机元素。否则将返回一个随机项。

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

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

toArray_.toArray(list) 源码
list(任何可以迭代的对象)创建一个真正的数组。用于转换 arguments 对象。

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

size_.size(list) 源码
返回 list 中的值的数量。

_.size([1, 2, 3, 4, 5]);
=> 5

_.size({one: 1, two: 2, three: 3});
=> 3

partition_.partition(list, predicate) 源码
list 拆分为两个数组:一个数组的元素都满足 predicate,另一个数组的元素都不满足 predicatepredicate 通过 iteratee 进行转换,以便于使用简写语法。

_.partition([0, 1, 2, 3, 4, 5], isOdd);
=> [[1, 3, 5], [0, 2, 4]]

compact_.compact(list) 源码
返回 list 的副本,其中删除了所有假值。在 JavaScript 中,falsenull0""undefinedNaN 都是假值。

_.compact([0, 1, false, 2, '', 3]);
=> [1, 2, 3]

数组函数

注意:所有数组函数也适用于 arguments 对象。但是,Underscore 函数并非设计用于处理“稀疏”数组。

first_.first(array, [n]) 别名: head, take 源码
返回 array 的第一个元素。传递 n 将返回数组的前 n 个元素。

_.first([5, 4, 3, 2, 1]);
=> 5

initial_.initial(array, [n]) 源码
返回除数组最后一个条目之外的所有内容。在 arguments 对象上特别有用。传递 n 以从结果中排除最后 n 个元素。

_.initial([5, 4, 3, 2, 1]);
=> [5, 4, 3, 2]

last_.last(array, [n]) 源码
返回 array 的最后一个元素。传递 n 将返回数组的最后 n 个元素。

_.last([5, 4, 3, 2, 1]);
=> 1

rest_.rest(array, [index]) 别名: tail, drop 源码
返回数组中元素的 rest。传递一个 index 以返回数组中从该索引开始的值。

_.rest([5, 4, 3, 2, 1]);
=> [4, 3, 2, 1]

flatten_.flatten(array, [depth]) 源码
展平嵌套的 array。如果传递true1作为 depth,则数组将只会被展平一层。传递更大的数字将导致展平操作更深入地进入嵌套层次结构。省略 depth 参数,或传递falseInfinity,将数组一直展平到最深的嵌套级别。

_.flatten([1, [2], [3, [[4]]]]);
=> [1, 2, 3, 4];

_.flatten([1, [2], [3, [[4]]]], true);
=> [1, 2, 3, [[4]]];

_.flatten([1, [2], [3, [[4]]]], 2);
=> [1, 2, 3, [4]];

without_.without(array, *values) 源码
返回 array 的副本,其中删除了所有 values 的实例。

_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
=> [2, 3, 4]

union_.union(*arrays) 源码
计算传入的 arrays 的并集:唯一项的列表,按顺序排列,这些项存在于一个或多个 arrays 中。

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

intersection_.intersection(*arrays) 源码
计算所有 arrays 的交集的值列表。结果中的每个值都存在于每个 arrays 中。

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]

difference_.difference(array, *others) 源码
类似于 without,但返回 array 中存在但 other 数组中不存在的值。

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

uniq_.uniq(array, [isSorted], [iteratee]) 别名: unique 源码
使用 === 测试对象相等性,生成 array 的无重复版本。特别是,只保留每个值的第一次出现。如果您事先知道 array 已排序,则传递 true 表示 isSorted 将运行速度更快的算法。如果要根据转换计算唯一项,请传递一个 iteratee 函数。

_.uniq([1, 2, 1, 4, 1, 3]);
=> [1, 2, 4, 3]

zip_.zip(*arrays) 源码
将每个 arrays 的值与其对应位置的值合并在一起。当您拥有通过匹配数组索引协调的独立数据源时,此功能非常有用。

_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]

unzip_.unzip(array) 别名: transpose 源码
zip 相反。给定一个数组的 array,返回一系列新数组,第一个数组包含输入数组中的所有第一个元素,第二个数组包含所有第二个元素,依此类推。如果您正在处理嵌套数组的矩阵,则可以使用此函数来转置矩阵。

_.unzip([["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]);
=> [['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]]

object_.object(list, [values]) 源码
将数组转换为对象。传递一个[key, value]对的列表,或一个键列表和一个值列表。按对传递是 pairs 的反向操作。如果存在重复的键,则最后一个值优先。

_.object(['moe', 'larry', 'curly'], [30, 40, 50]);
=> {moe: 30, larry: 40, curly: 50}

_.object([['moe', 30], ['larry', 40], ['curly', 50]]);
=> {moe: 30, larry: 40, curly: 50}

chunk_.chunk(array, length) 源码
array 分块为多个数组,每个数组包含 length 个或更少的项目。

var partners = _.chunk(_.shuffle(kindergarten), 2);
=> [["Tyrone", "Elie"], ["Aidan", "Sam"], ["Katrina", "Billie"], ["Little Timmy"]]

indexOf_.indexOf(array, value, [isSorted]) 源码
返回在 array 中找到 value 的索引,如果 array 中不存在 value,则返回 -1。如果您正在处理一个大型数组,并且您知道该数组已经排序,请传递true表示 isSorted 以使用更快的二分搜索...或者,传递一个数字作为第三个参数,以便在给定索引之后查找数组中的第一个匹配值。如果isSortedtrue,则此函数使用运算符<(注意)。

_.indexOf([1, 2, 3], 2);
=> 1

lastIndexOf_.lastIndexOf(array, value, [fromIndex]) 源码
返回 数组 中最后一次出现 的索引,如果该值不存在,则返回 -1。传递 fromIndex 以从给定索引开始搜索。

_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
=> 4

sortedIndex_.sortedIndex(array, value, [iteratee], [context]) 来源
使用二分搜索来确定 应该 插入到 数组 中以维持 数组 排序顺序的最小索引。如果提供了 迭代函数,它将用于计算每个值的排序等级,包括您传递的 。迭代函数也可以是要排序的属性的字符串名称(例如。length)。此函数使用运算符<(注意)。

_.sortedIndex([10, 20, 30, 40, 50], 35);
=> 3

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

findIndex_.findIndex(array, predicate, [context]) 来源
类似于 _.indexOf,返回 谓词 真值测试通过的第一个索引;否则返回 -1

_.findIndex([4, 6, 8, 12], isPrime);
=> -1 // not found
_.findIndex([4, 6, 7, 12], isPrime);
=> 2

findLastIndex_.findLastIndex(array, predicate, [context]) 来源
类似于 _.findIndex,但以相反的顺序迭代数组,返回最接近 谓词 真值测试通过的末尾的索引。

var users = [{'id': 1, 'name': 'Bob', 'last': 'Brown'},
             {'id': 2, 'name': 'Ted', 'last': 'White'},
             {'id': 3, 'name': 'Frank', 'last': 'James'},
             {'id': 4, 'name': 'Ted', 'last': 'Jones'}];
_.findLastIndex(users, {
  name: 'Ted'
});
=> 3

range_.range([start], stop, [step]) 来源
一个创建灵活编号的整数列表的函数,便于each映射循环。开始(start)如果省略,则默认为 0步长(step)默认为 1(如果 开始停止 之前),否则为 -1。返回一个从 开始(包含)到 停止(不包含)的整数列表,按 步长递增(或递减)。

_.range(10);
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11);
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5);
=> [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1);
=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0);
=> []

函数(呃,咳咳)函数

bind_.bind(function, object, *arguments) 来源
函数 绑定到 对象,这意味着无论何时调用该函数,this 的值都将是该 对象。或者,将 参数 传递给 函数 以预先填充它们,也称为 部分应用。对于没有上下文绑定的部分应用,请使用 partial

var func = function(greeting){ return greeting + ': ' + this.name };
func = _.bind(func, {name: 'moe'}, 'hi');
func();
=> 'hi: moe'

bindAll_.bindAll(object, *methodNames) 来源
绑定 对象 上的多个方法(由 methodNames 指定),以便在调用它们时在该对象的上下文中运行。这对于绑定将用作事件处理程序的函数非常方便,否则将使用相当无用的 this 调用这些函数。methodNames 是必需的。

var buttonView = {
  label  : 'underscore',
  onClick: function(){ alert('clicked: ' + this.label); },
  onHover: function(){ console.log('hovering: ' + this.label); }
};
_.bindAll(buttonView, 'onClick', 'onHover');
// When the button is clicked, this.label will have the correct value.
jQuery('#underscore_button').on('click', buttonView.onClick);

partial_.partial(function, *arguments) 来源
通过填充任意数量的 参数 来部分应用函数,而不会 更改其动态this值。与 bind 非常相似。您可以传递_参数 列表中指定一个不应预先填充的参数,而是在调用时提供。注意:如果您同时需要 _ 占位符和 this 绑定,请同时使用 _.partial_.bind

var subtract = function(a, b) { return b - a; };
sub5 = _.partial(subtract, 5);
sub5(20);
=> 15

// Using a placeholder
subFrom20 = _.partial(subtract, _, 20);
subFrom20(5);
=> 15

memoize_.memoize(function, [hashFunction]) 来源
通过缓存计算结果来记忆给定的 函数。对于加速运行缓慢的计算很有用。如果传递了可选的 hashFunction,它将用于计算存储结果的哈希键,该键基于原始函数的参数。默认的 hashFunction 仅使用记忆函数的第一个参数作为键。记忆值的缓存可作为缓存属性在返回的函数上可用。

var fibonacci = _.memoize(function(n) {
  return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
});

delay_.delay(function, wait, *arguments) 来源
setTimeout 非常相似,在 等待 毫秒后调用 函数。如果您传递可选的 参数,它们将在调用 函数 时转发给它。

var log = _.bind(console.log, console);
_.delay(log, 1000, 'logged later');
=> 'logged later' // Appears after one second.

defer_.defer(function, *arguments) 来源
推迟调用 函数,直到当前调用堆栈清除为止,类似于使用延迟为 0 的 setTimeout。这对于执行昂贵的计算或分块渲染 HTML 而不阻塞 UI 线程更新非常有用。如果您传递可选的 参数,它们将在调用 函数 时转发给它。

_.defer(function(){ alert('deferred'); });
// Returns from the function before the alert runs.

throttle_.throttle(function, wait, [options]) 来源
创建并返回传递函数的新节流版本,该版本在重复调用时,每 等待 毫秒最多只实际调用一次原始函数。对于限制发生频率超过您处理能力的事件很有用。

默认情况下,throttle 会在您第一次调用该函数时立即执行它,并且,如果您在 等待 期间再次调用它任意次数,则会在该时间段结束后立即执行。如果您想禁用前沿调用,请传递{leading: false},如果您想禁用后沿执行,请传递
{trailing: false}.

var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);

如果您需要取消预定的节流,可以调用.cancel()在节流函数上。

debounce_.debounce(function, wait, [immediate]) 来源
创建并返回传递函数的新去抖动版本,该版本将推迟其执行,直到自上次调用后经过 等待 毫秒为止。对于实现仅在输入停止到达 之后 才应该发生的行为很有用。例如:渲染 Markdown 评论的预览,在窗口停止调整大小后重新计算布局,等等。

等待 时间间隔结束时,将使用 最近 传递给去抖动函数的参数调用该函数。

传递true对于 immediate 参数,使 debounce等待 时间间隔的前沿而不是后沿触发该函数。在防止“提交”按钮上的意外双击第二次触发等情况下很有用。

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

如果您需要取消预定的去抖动,可以调用.cancel()在去抖动函数上。

once_.once(function) 来源
创建只能调用一次的函数版本。重复调用修改后的函数将不起作用,返回原始调用的值。对于初始化函数很有用,而不必设置布尔标志然后稍后检查它。

var initialize = _.once(createApplication);
initialize();
initialize();
// Application is only created once.

after_.after(count, function) 来源
创建 函数 的包装器,该包装器最初不执行任何操作。从第 计数 次调用开始,它开始实际调用 函数。对于分组异步响应很有用,在继续之前,您希望确保所有异步调用都已完成。

var renderNotes = _.after(notes.length, render);
_.each(notes, function(note) {
  note.asyncSave({success: renderNotes});
});
// renderNotes is run once, after all notes have saved.

before_.before(count, function) 来源
创建 函数 的包装器,该包装器记忆其返回值。从第 计数 次调用开始,立即返回上次调用的记忆结果,而不是再次调用 函数。因此,包装器最多调用 函数 计数 - 1 次。

var monthlyMeeting = _.before(3, askForRaise);
monthlyMeeting();
monthlyMeeting();
monthlyMeeting();
// the result of any subsequent calls is the same as the second call

wrap_.wrap(function, wrapper) 来源
将第一个 函数 包装在 包装器 函数中,并将其作为第一个参数传递。这允许 包装器函数 运行之前和之后执行代码,调整参数并有条件地执行它。

var hello = function(name) { return "hello: " + name; };
hello = _.wrap(hello, function(func) {
  return "before, " + func("moe") + ", after";
});
hello();
=> 'before, hello: moe, after'

negate_.negate(predicate) 来源
返回 谓词 函数的新否定版本。

var isFalsy = _.negate(Boolean);
_.find([-2, -1, 0, 1, 2], isFalsy);
=> 0

compose_.compose(*functions) 来源
返回 函数 列表的组合,其中每个函数都使用其后函数的返回值。用数学术语来说,组合函数 f()g()h() 会生成 f(g(h()))

var greet    = function(name){ return "hi: " + name; };
var exclaim  = function(statement){ return statement.toUpperCase() + "!"; };
var welcome = _.compose(greet, exclaim);
welcome('moe');
=> 'hi: MOE!'

restArguments_.restArguments(function, [startIndex]) 来源
返回 函数 的一个版本,该版本在被调用时,会将从 startIndex 及其后的所有参数收集到一个数组中。如果您没有传递显式的 startIndex,它将通过查看 函数 本身的参数数量来确定。类似于 ES6 的 rest 参数语法

var raceResults = _.restArguments(function(gold, silver, bronze, everyoneElse) {
  _.each(everyoneElse, sendConsolations);
});

raceResults("Dopey", "Grumpy", "Happy", "Sneezy", "Bashful", "Sleepy", "Doc");

对象函数

keys_.keys(object) 来源
检索 对象 自身所有可枚举属性的名称。

_.keys({one: 1, two: 2, three: 3});
=> ["one", "two", "three"]

allKeys_.allKeys(object) 来源
检索 对象 自身及其继承的所有属性的名称。

function Stooge(name) {
  this.name = name;
}
Stooge.prototype.silly = true;
_.allKeys(new Stooge("Moe"));
=> ["name", "silly"]

values_.values(object) 来源
返回 对象 自身所有属性的值。

_.values({one: 1, two: 2, three: 3});
=> [1, 2, 3]

mapObject_.mapObject(object, iteratee, [context]) 来源
类似于 map,但用于对象。依次转换每个属性的值。

_.mapObject({start: 5, end: 12}, function(val, key) {
  return val + 5;
});
=> {start: 10, end: 17}

pairs_.pairs(object) 来源
将对象转换为[key, value]键值对列表。与 object 相反。

_.pairs({one: 1, two: 2, three: 3});
=> [["one", 1], ["two", 2], ["three", 3]]

invert_.invert(object) 来源
返回 对象 的副本,其中键已成为值,值已成为键。为此,您的对象的所有值都应该是唯一的并且可以字符串化。

_.invert({Moe: "Moses", Larry: "Louis", Curly: "Jerome"});
=> {Moses: "Moe", Louis: "Larry", Jerome: "Curly"};

create_.create(prototype, props) 来源
使用给定的原型创建一个新对象,可以选择将 props 作为 自身 属性附加。基本上,Object.create,但没有所有属性描述符的麻烦。

var moe = _.create(Stooge.prototype, {name: "Moe"});

functions_.functions(object) 别名:methods 来源
返回对象中每个方法名称的排序列表,也就是说,对象的每个函数属性的名称。

_.functions(_);
=> ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...

findKey_.findKey(object, predicate, [context]) 来源
类似于 _.findIndex,但用于对象中的键。返回 谓词 真值测试通过的 undefined谓词 通过 迭代函数 进行转换以方便简写语法。

extend_.extend(destination, *sources) 来源
对象中的所有属性浅复制到 目标 对象,并返回 目标 对象。任何嵌套的对象或数组都将按引用复制,而不是复制。它是按顺序进行的,因此最后一个源将覆盖先前参数中同名属性的值。

_.extend({name: 'moe'}, {age: 50});
=> {name: 'moe', age: 50}

extendOwn_.extendOwn(destination, *sources) 别名:assign 来源
类似于 extend,但仅将 自身 属性复制到目标对象。

pick_.pick(object, *keys) 来源
返回 对象 的副本,过滤后仅包含允许的 (或有效键数组)的值。或者接受一个谓词,指示要选取哪些键。

_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age');
=> {name: 'moe', age: 50}
_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
  return _.isNumber(value);
});
=> {age: 50}

omit_.omit(object, *keys) 来源
返回 对象 的副本,过滤后省略不允许的 (或键数组)。或者接受一个谓词,指示要省略哪些键。

_.omit({name: 'moe', age: 50, userid: 'moe1'}, 'userid');
=> {name: 'moe', age: 50}
_.omit({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
  return _.isNumber(value);
});
=> {name: 'moe', userid: 'moe1'}

defaults_.defaults(object, *defaults) 来源
在用以下 默认值 对象列表中出现的第一个值填充其undefined属性后返回 对象

var iceCream = {flavor: "chocolate"};
_.defaults(iceCream, {flavor: "vanilla", sprinkles: "lots"});
=> {flavor: "chocolate", sprinkles: "lots"}

clone_.clone(object) 来源
创建提供的 普通 对象 的浅拷贝副本。任何嵌套的对象或数组都将按引用复制,而不是复制。

_.clone({name: 'moe'});
=> {name: 'moe'};

tap_.tap(object, interceptor) 来源
使用 对象 调用 拦截器,然后返回 对象。此方法的主要目的是“插入”方法链,以便对链中的中间结果执行操作。

_.chain([1,2,3,200])
  .filter(function(num) { return num % 2 == 0; })
  .tap(alert)
  .map(function(num) { return num * num })
  .value();
=> // [2, 200] (alerted)
=> [4, 40000]

toPath_.toPath(path) 源代码
确保 path 是一个数组。如果 path 是一个字符串,它将被包装在一个单元素数组中;如果它已经是一个数组,则不加修改地返回。

_.toPath('key');
=> ['key']
_.toPath(['a', 0, 'b']);
=> ['a', 0, 'b'] // (same array)

_.toPath在以下函数中被内部使用:has, get, invoke, property, propertyOfresult,以及在 iteratee 和所有依赖它的函数中,以便规范化深层属性路径。您可以覆盖_.toPath如果您想自定义此行为,例如启用类似 Lodash 的字符串路径简写。请注意,更改_.toPath将不可避免地导致某些键变得不可访问;请自行承担覆盖的风险。

// Support dotted path shorthands.
var originalToPath = _.toPath;
_.mixin({
  toPath: function(path) {
    return _.isString(path) ? path.split('.') : originalToPath(path);
  }
});
_.get({a: [{b: 5}]}, 'a.0.b');
=> 5

get_.get(object, path, [default]) 源代码
返回 object 的指定属性。path 可以指定为一个简单的键,也可以指定为一个对象键或数组索引的数组,用于深层属性获取。如果该属性不存在或为undefined,则返回可选的 default

_.get({a: 10}, 'a');
=> 10
_.get({a: [{b: 2}]}, ['a', 0, 'b']);
=> 2
_.get({a: 10}, 'b', 100);
=> 100

has_.has(object, key) 源代码
对象是否包含给定的键?与object.hasOwnProperty(key)相同,但使用对hasOwnProperty函数的安全引用,以防它被 意外覆盖

_.has({a: 1, b: 2, c: 3}, "b");
=> true

property_.property(path) 源代码
返回一个函数,该函数将返回任何传入对象的指定属性。path可以指定为一个简单的键,也可以指定为一个对象键或数组索引的数组,用于深层属性获取。

var stooge = {name: 'moe'};
'moe' === _.property('name')(stooge);
=> true

var stooges = {moe: {fears: {worst: 'Spiders'}}, curly: {fears: {worst: 'Moe'}}};
var curlysWorstFear = _.property(['curly', 'fears', 'worst']);
curlysWorstFear(stooges);
=> 'Moe'

propertyOf_.propertyOf(object) 源代码
_.property相反。接受一个对象并返回一个函数,该函数将返回提供的属性的值。

var stooge = {name: 'moe'};
_.propertyOf(stooge)('name');
=> 'moe'

matcher_.matcher(attrs) 别名:matches 源代码
返回一个谓词函数,该函数将告诉您传入的对象是否包含 attrs 中存在的所有键/值属性。

var ready = _.matcher({selected: true, visible: true});
var readyToGoList = _.filter(list, ready);

isEqual_.isEqual(object, other) 源代码
对两个对象执行优化的深度比较,以确定它们是否应视为相等。

var stooge = {name: 'moe', luckyNumbers: [13, 27, 34]};
var clone  = {name: 'moe', luckyNumbers: [13, 27, 34]};
stooge == clone;
=> false
_.isEqual(stooge, clone);
=> true

isMatch_.isMatch(object, properties) 源代码
告诉您 properties 中的键和值是否包含在 object 中。

var stooge = {name: 'moe', age: 32};
_.isMatch(stooge, {age: 32});
=> true

isEmpty_.isEmpty(collection) 源代码
如果 collection 没有元素,则返回 true。对于字符串和类数组对象,_.isEmpty检查 length 属性是否为 0。对于其他对象,如果该对象没有可枚举的自有属性,则返回 true。请注意,根据此定义,原始数字、布尔值和符号始终为空。

_.isEmpty([1, 2, 3]);
=> false
_.isEmpty({});
=> true

isElement_.isElement(object) 源代码
如果 object 是 DOM 元素,则返回 true

_.isElement(jQuery('body')[0]);
=> true

isArray_.isArray(object) 源代码
如果 object 是数组,则返回 true

(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true

isObject_.isObject(value) 源代码
如果 value 是对象,则返回 true。请注意,JavaScript 数组和函数是对象,而(普通)字符串和数字不是。

_.isObject({});
=> true
_.isObject(1);
=> false

isArguments_.isArguments(object) 源代码
如果 object 是 Arguments 对象,则返回 true

(function(){ return _.isArguments(arguments); })(1, 2, 3);
=> true
_.isArguments([1,2,3]);
=> false

isFunction_.isFunction(object) 源代码
如果 object 是函数,则返回 true

_.isFunction(alert);
=> true

isString_.isString(object) 源代码
如果 object 是字符串,则返回 true

_.isString("moe");
=> true

isNumber_.isNumber(object) 源代码
如果 object 是数字(包括NaN).

_.isNumber(8.4 * 5);
=> true

isFinite_.isFinite(object) 源代码
如果 object 是有限数字,则返回 true

_.isFinite(-101);
=> true

_.isFinite(-Infinity);
=> false

isBoolean_.isBoolean(object) 源代码
如果 objecttruefalse,则返回 true

_.isBoolean(null);
=> false

isDate_.isDate(object) 源代码
如果 object 是日期,则返回 true

_.isDate(new Date());
=> true

isRegExp_.isRegExp(object) 源代码
如果 object 是正则表达式,则返回 true

_.isRegExp(/moe/);
=> true

isError_.isError(object) 源代码
如果 object 继承自 Error,则返回 true

try {
  throw new TypeError("Example");
} catch (o_O) {
  _.isError(o_O);
}
=> true

isSymbol_.isSymbol(object) 源代码
如果 objectSymbol,则返回 true

_.isSymbol(Symbol());
=> true

isMap_.isMap(object) 源代码
如果 objectMap,则返回 true

_.isMap(new Map());
=> true

isWeakMap_.isWeakMap(object) 源代码
如果 objectWeakMap,则返回 true

_.isWeakMap(new WeakMap());
=> true

isSet_.isSet(object) 源代码
如果 objectSet,则返回 true

_.isSet(new Set());
=> true

isWeakSet_.isWeakSet(object) 源代码
如果 objectWeakSet,则返回 true

_.isWeakSet(WeakSet());
=> true

isArrayBuffer_.isArrayBuffer(object) 源代码
如果 objectArrayBuffer,则返回 true

_.isArrayBuffer(new ArrayBuffer(8));
=> true

isDataView_.isDataView(object) 源代码
如果 objectDataView,则返回 true

_.isDataView(new DataView(new ArrayBuffer(8)));
=> true

isTypedArray_.isTypedArray(object) 源代码
如果 objectTypedArray,则返回 true

_.isTypedArray(new Int8Array(8));
=> true

isNaN_.isNaN(object) 源代码
如果 objectNaN,则返回 true
注意:这与原生的 isNaN 函数不同,后者对于许多其他非数字值也会返回 true,例如undefined.

_.isNaN(NaN);
=> true
isNaN(undefined);
=> true
_.isNaN(undefined);
=> false

isNull_.isNull(object) 源代码
如果 object 的值为 null,则返回 true

_.isNull(null);
=> true
_.isNull(undefined);
=> false

isUndefined_.isUndefined(value) 源代码
如果 valueundefined,则返回 true

_.isUndefined(window.missingVariable);
=> true

实用函数

noConflict_.noConflict() 源代码
将全局_变量的控制权交还给其先前的所有者。返回对 Underscore 对象的引用。

var underscore = _.noConflict();

如果您使用 EcmaScript 6、AMD 或 CommonJS 模块系统导入 Underscore,则_.noConflict函数不存在。

identity_.identity(value) 源代码
返回与用作参数的值相同的值。在数学中,f(x) = x
此函数看起来没用,但在整个 Underscore 中用作默认迭代器。

var stooge = {name: 'moe'};
stooge === _.identity(stooge);
=> true

constant_.constant(value) 源代码
创建一个函数,该函数返回与用作_.constant.

var stooge = {name: 'moe'};
stooge === _.constant(stooge)();
=> true

参数的值相同的值。
noop_.noop() 源代码undefined返回

obj.initialize = _.noop;

,而不管传递给它的参数是什么。可用作可选回调参数的默认值。
times_.times(n, iteratee, [context]) 源代码index调用给定的迭代器函数 n 次。每次调用 iteratee 时都会传递一个

_.times(3, function(n){ genie.grantWishNumber(n); });

参数。生成一个包含返回值的数组。
random_.random(min, max) 源代码0返回 minmax 之间的随机整数,包括 minmax。如果只传递一个参数,它将返回

_.random(0, 100);
=> 42

和该数字之间的数字。
mixin_.mixin(object) 源代码允许您使用自己的实用函数扩展 Underscore。传递一个{name: function}

_.mixin({
  capitalize: function(string) {
    return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
  }
});
_("fabio").capitalize();
=> "Fabio"

定义的哈希表,将您的函数添加到 Underscore 对象以及 OOP 包装器中。返回 Underscore 对象以方便链接。
iteratee_.iteratee(value, [context]) 源代码生成一个回调函数,该函数可以应用于集合中的每个元素。_.iterateevalue支持许多用于常见回调用例的简写语法。根据生成一个回调函数,该函数可以应用于集合中的每个元素。的类型,

// No value
_.iteratee();
=> _.identity()

// Function
_.iteratee(function(n) { return n * 2; });
=> function(n) { return n * 2; }

// Object
_.iteratee({firstName: 'Chelsea'});
=> _.matcher({firstName: 'Chelsea'});

// Anything else
_.iteratee('firstName');
=> _.property('firstName');

将返回生成一个回调函数,该函数可以应用于集合中的每个元素。: 以下 Underscore 方法通过, countBy, every, filter, find, findIndex, findKey, groupBy, findLastIndex, 映射, indexBy, mapObject, max, min, partition, reject, some, sortBysortedIndex

uniq生成一个回调函数,该函数可以应用于集合中的每个元素。转换其谓词。您可以覆盖

// Support `RegExp` predicate shorthand.
var builtinIteratee = _.iteratee;
_.iteratee = function(value, context) {
  if (_.isRegExp(value)) return function(obj) { return value.test(obj) };
  return builtinIteratee(value, context);
};

如果您需要其他或不同的简写语法。
uniqueId_.uniqueId([prefix]) 源代码

_.uniqueId('contact_');
=> 'contact_104'

为需要全局唯一 ID 的客户端模型或 DOM 元素生成一个全局唯一 ID。如果传递了 prefix,则 ID 将附加到它后面。
escape_.escape(string) 源代码&, <, >, ", `sortedIndex'转义字符串以插入 HTML,替换

_.escape('Curly, Larry & Moe');
=> "Curly, Larry &amp; Moe"

字符。
unescape_.unescape(string) 源代码escape 相反,将, &amp;, &lt;, &gt;, &quot;&#x60;&#x27;

_.unescape('Curly, Larry &amp; Moe');
=> "Curly, Larry & Moe"

替换为其未转义的对应字符。
result_.result(object, property, [defaultValue]) 源代码如果名为 property 的属性的值是一个函数,则以 object 为上下文调用它;否则,返回它。如果提供了默认值,并且该属性不存在或未定义,则将返回默认值。如果defaultValue

var object = {cheese: 'crumpets', stuff: function(){ return 'nonsense'; }};
_.result(object, 'cheese');
=> "crumpets"
_.result(object, 'stuff');
=> "nonsense"
_.result(object, 'meat', 'ham');
=> "ham"

是一个函数,则将返回其结果。
now_.now() 源代码

_.now();
=> 1392066795351

使用运行时中最快的可用方法返回当前时间的整数时间戳。用于实现计时/动画函数。
template_.template(templateString, [settings]) 源代码将 JavaScript 模板编译成可用于渲染的函数。用于从 JSON 数据源渲染复杂的 HTML 片段。模板函数既可以插入值,使用<%= … %>,也可以执行任意 JavaScript 代码,使用<% … %>。如果要插入一个值并对其进行 HTML 转义,请使用<%- … %>。评估模板函数时,请传入一个 data 对象,该对象具有与模板的自由变量相对应的属性。settings 参数应该是一个哈希表,其中包含任何应被覆盖的_.templateSettings

var compiled = _.template("hello: <%= name %>");
compiled({name: 'moe'});
=> "hello: moe"

var template = _.template("<b><%- value %></b>");
template({value: '<script>'});
=> "<b>&lt;script&gt;</b>"

。您也可以使用print从 JavaScript 代码中。这有时比使用<%= ... %>.

var compiled = _.template("<% print('Hello ' + epithet); %>");
compiled({epithet: "stooge"});
=> "Hello stooge"

如果 ERB 风格的分隔符不适合您,您可以更改 Underscore 的模板设置以使用不同的符号来分隔插值代码。定义一个 interpolate 正则表达式来匹配应该逐字插值的表达式,一个 escape 正则表达式来匹配应该在 HTML 转义后插入的表达式,以及一个 evaluate 正则表达式来匹配应该在不插入到结果字符串的情况下进行评估的表达式。请注意,如果您的模板的一部分匹配多个正则表达式,则将按以下优先级顺序应用第一个:(1) escape,(2) interpolate,(3) evaluate。您可以定义或省略这三个中的任何组合。例如,要执行 Mustache.js 风格的模板

_.templateSettings = {
  interpolate: /\{\{(.+?)\}\}/g
};

var template = _.template("Hello {{ name }}!");
template({name: "Mustache"});
=> "Hello Mustache!"

默认情况下,template 通过以下方式将数据中的值放入本地作用域with语句。但是,您可以使用 variable 设置指定单个变量名。这可以显著提高模板的渲染速度。

_.template("Using 'with': <%= data.answer %>", {variable: 'data'})({answer: 'no'});
=> "Using 'with': no"

预编译模板对于调试无法重现的错误有很大帮助。这是因为预编译的模板可以提供行号和堆栈跟踪,而这在客户端编译模板时是不可能的。source 属性在编译后的模板函数中可用,以便于预编译。

<script>
  JST.project = <%= _.template(jstText).source %>;
</script>

面向对象风格

您可以根据自己的喜好以面向对象或函数式风格使用 Underscore。以下两行代码是将数字列表加倍的相同方法。sourcesource

_.map([1, 2, 3], function(n){ return n * 2; });
_([1, 2, 3]).map(function(n){ return n * 2; });

链式调用

调用chain将导致所有未来的方法调用都返回包装对象。完成计算后,调用value以检索最终值。下面是一个将 map/flatten/reduce 链接在一起的示例,以便获取歌曲中每个单词的计数。

var lyrics = [
  {line: 1, words: "I'm a lumberjack and I'm okay"},
  {line: 2, words: "I sleep all night and I work all day"},
  {line: 3, words: "He's a lumberjack and he's okay"},
  {line: 4, words: "He sleeps all night and he works all day"}
];

_.chain(lyrics)
  .map(function(line) { return line.words.split(' '); })
  .flatten()
  .reduce(function(counts, word) {
    counts[word] = (counts[word] || 0) + 1;
    return counts;
  }, {})
  .value();

=> {lumberjack: 2, all: 4, night: 2 ... }

此外,数组原型的函数 通过链接的 Underscore 对象进行代理,因此您可以将reversepush放入您的链中,并继续修改数组。

chain_.chain(obj) source
返回一个包装对象。在此对象上调用方法将继续返回包装对象,直到value被调用。

var stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}];
var youngest = _.chain(stooges)
  .sortBy(function(stooge){ return stooge.age; })
  .map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
  .first()
  .value();
=> "moe is 21"

value_.chain(obj).value() source
提取包装对象的值。

_.chain([1, 2, 3]).reverse().value();
=> [3, 2, 1]

Underscore.lua,两种语言都适用的函数的 Lua 端口。包括 OOP 包装和链接。(source

Dollar.swift,许多 Underscore.js 函数等的 Swift 端口。(source

Underscore.m,许多 Underscore.js 函数的 Objective-C 端口,使用鼓励链接的语法。(source

_.m,另一个 Objective-C 端口,它试图更接近原始的 Underscore.js API。(source

Underscore.php,两种语言都适用的函数的 PHP 端口。专为 PHP 5.4 量身定制,并考虑了数据类型容忍度。(source

Underscore-perl,许多 Underscore.js 函数的 Perl 端口,针对 Perl 哈希和数组。(source

Underscore.cfc,许多 Underscore.js 函数的 Coldfusion 端口。(source

Underscore.string,一个 Underscore 扩展,添加了用于字符串操作的函数trim, startsWith, contains, capitalize, reverse, sprintf, 等等。

Underscore-java,两种语言都适用的函数的 Java 端口。包括 OOP 包装和链接。(source

Ruby 的 Enumerable 模块。

Prototype.js,它以最接近 Ruby 的 Enumerable 的方式为 JavaScript 提供集合函数。

Oliver Steele 的 Functional JavaScript,其中包括全面的高阶函数支持以及字符串 lambda。

Michael Aufreiter 的 Data.js,一个用于 JavaScript 的数据操作 + 持久化库。

Python 的 itertools

PyToolz,一个 Python 端口,扩展了 itertools 和 functools 以包含大部分 Underscore API。

Funcy,一个实用的 Python 函数式助手集合,部分灵感来自 Underscore。

备注

关于在 Underscore 中使用<
依赖于排序的 Underscore 函数,例如 _.sortBy_.sortedIndex,使用 JavaScript 内置的 关系运算符,特别是“小于”运算符<。重要的是要了解这些运算符仅对数字和字符串有意义。您可以向它们抛出任何值,但 JavaScript 会在执行实际比较之前先将操作数转换为字符串或数字。如果传递的操作数无法有意义地转换为字符串或数字,则它最终将是NaN默认情况下。此值不可排序。

理想情况下,您要排序的值应该都是(可以有意义地转换为)字符串或都是(可以有意义地转换为)数字。如果不是这种情况,您有两个选择

更新日志

1.13.62022 年 9 月 24 日差异文档
版本 1.13.5 的热修复程序,用于从 package.json 中删除postinstall脚本,该脚本意外破坏了许多人的构建。

1.13.52022 年 9 月 23 日差异文档

1.13.42022 年 6 月 2 日差异文档

1.13.32022 年 4 月 23 日差异文档

1.13.22021 年 12 月 16 日差异文档

1.13.12021 年 4 月 15 日差异文档

1.13.02021 年 4 月 9 日差异文档

1.13.0-32021 年 3 月 31 日差异文档

1.13.0-22021 年 3 月 15 日差异文档

1.12.12021 年 3 月 15 日差异文档

1.13.0-12021 年 3 月 11 日差异文档

1.13.0-02021 年 3 月 9 日差异文档

1.12.02020 年 11 月 24 日差异文档

精简了用于测试的开发依赖项。

修复了 1.9.0 版中引入的一个回归,该回归导致

而不是绑定对象。

用中性的“允许”/“不允许”术语替换注释和文档中带有歧视性的“白名单”/“黑名单”术语。

始终返回下界,即

可以插入

单元测试的表示法与其他单元测试一致。

_.isSymbol

返回的函数现在有一个

_.range

添加了对多种环境的支持,包括:WebWorkers、browserify 和 ES6 导入。

添加了

_.some

1.5.22013年9月7日差异文档

1.5.12013年7月8日差异文档

1.5.02013年7月6日差异文档

1.4.42013年1月30日差异文档

1.4.32012年12月4日差异文档

1.4.22012年10月6日差异文档

1.4.12012年10月1日差异文档

1.4.02012年9月27日差异文档

1.3.32012年4月10日差异文档

1.3.12012年1月23日差异文档

1.3.02012年1月11日差异文档

1.2.42012年1月4日差异文档

1.2.32011年12月7日差异文档

1.2.22011年11月14日差异文档

1.2.12011年10月24日差异文档

1.2.02011年10月5日差异文档

1.1.72011年7月13日差异文档
删除了_.max,它将集合聚合成类似项目的组。添加了reduceRightfilter,以补充(重命名的)_.intersection。对稀疏数组的支持进行了各种改进。_.toArray现在在直接传递数组时返回一个克隆。_.functions现在还返回原型链中存在的函数的名称。

1.1.62011年4月18日差异文档
删除了_.isMatch,它将返回一个函数,该函数仅在第一次被调用指定次数后才运行。_.invoke现在可以接受直接的函数引用。_.every现在需要传递一个迭代器函数,这反映了 ES5 API。_.create在值为 undefined 时不再复制键。_.bind现在在尝试绑定未定义的值时会出错。

1.1.52011年3月20日差异文档
恢复了 1.8.1 中更改的先前旧 Internet Explorer 和相关边缘情况行为。弃用了函数,用于合并表示默认选项的 JS 对象。添加了一个_.once函数,用于制造应该只执行一次的函数。_.bind现在委托给原生 ES5 版本(如果可用)。样式的过滤,或采用函数作为自定义回调。现在在非对象值上使用时会抛出错误,如 ES5 中所示。修复了样式的过滤,或采用函数作为自定义回调。在稀疏数组上使用时的错误。

1.1.42011 年 1 月 9 日差异文档
在传递null作为值时,改进了与 ES5 的数组方法的兼容性。_.wrap现在可以正确设置this为包装函数。对象时出现的错误现在接受一个可选标志,用于在保证已排序的数组中查找插入索引。避免使用.callee,以允许_.isArray在 ES5 的严格模式下正常工作。

1.1.32010 年 12 月 1 日差异文档
在 CommonJS 中,现在可以使用以下命令来请求 Underscore
var _ = require("underscore")。添加了修复了 1.9.0 中的边缘情况回归,包括在空数组上调用_.debounce函数。删除了_.breakLoop,取而代之的是 ES5 风格的不可中断的 each 实现 - 这删除了 try/catch,现在您将获得更好的堆栈跟踪,用于在 Underscore 迭代器中抛出的异常。改进了 isType 函数系列,以便更好地与 Internet Explorer 主机对象互操作。_.template现在可以正确转义模板中的反斜杠。改进了_.reduce与 ES5 版本的兼容性:如果您没有传递初始值,则使用集合中的第一个项目。样式的查找,采用对象以进行不再返回迭代的集合,以提高与 ES5 的——一种不太有用的.

1.1.22010 年 10 月 15 日差异文档
修复了现在接受键和索引数组作为路径说明符,用于查找值的深层属性。的一致性,它错误地指向了_.intersect修复了一个导致_.include,就像它应该指向的那样。添加了_.unique作为_.uniq.

1.1.12010 年 10 月 5 日差异文档
提高了_.template的速度及其对多行插值的处理。Ryan Tenney 为许多 Underscore 函数贡献了优化。现在提供源代码的注释版本。

1.1.02010 年 8 月 18 日差异文档
的 方法签名已更改为与 ES5 签名匹配,而不是 Ruby/Prototype.js 版本。这是一个向后不兼容的更改。_.reduce现在可以在没有参数的情况下调用,并保留空格。_.template现在接受键和索引数组作为路径说明符,用于查找值的深层属性。的新别名。_.include.

1.0.42010 年 6 月 22 日差异文档
Andri Möll 贡献了some函数,该函数可用于通过缓存结果来加速昂贵的重复计算。

1.0.32010 年 6 月 14 日差异文档
使_.isEqual返回false的补丁,如果比较对象的任何属性具有NaN值。从技术上讲,这是正确的做法,但语义上值得怀疑。注意 NaN 比较。

1.0.22010 年 3 月 23 日差异文档
修复了_.isArguments在最新版本的 Opera 中,它将 arguments 对象作为真正的数组。

1.0.12010 年 3 月 19 日差异文档
修复了_.isEqual在比较两个具有相同数量的未定义键但名称不同的对象时的错误。

1.0.02010 年 3 月 18 日差异文档
几个月来,情况一直很稳定,因此 Underscore 现在被认为已经脱离测试版,版本为 1.0。自 0.6 以来的改进包括_.isBoolean,以及_.create能够接受多个源对象。

0.6.02010 年 2 月 24 日差异文档
主要版本。包含了许多 Mile Frawley 对集合函数进行更安全的鸭子类型重构,以及更简洁的内部结构。一个新的_.mixin方法,允许您使用自己的实用函数扩展 Underscore。添加了_.times,它与 Ruby 或 Prototype.js 中的工作方式相同。对 ES5 的Array.isArraysortedIndexObject.keys.

0.5.82010 年 1 月 28 日差异文档
修复了 Underscore 的集合函数,使其可以再次在 NodeListHTMLCollection 上工作,这要感谢 Justin Tulloss

0.5.72010 年 1 月 20 日差异文档
更安全的_.isArguments实现,以及更快的_.isNumber,
,这要感谢 Jed Schmidt

0.5.62010 年 1 月 18 日差异文档
可自定义的_.template分隔符,由 Noah Sloan 贡献。

0.5.52010 年 1 月 9 日差异文档
修复了 MobileSafari 的 OOP 包装器中关于 arguments 对象的错误。

0.5.42010 年 1 月 5 日差异文档
修复了_.template的模板字符串中包含多个单引号的错误。请参阅:Rick Strahl 的博客文章

0.5.22010 年 1 月 1 日差异文档
新的isArray, isDate, isFunction, isNumber, isRegExpsortedIndexisString实现,这要感谢 Robert Kieffer 的建议。它们现在不再进行Object#toString比较,而是检查预期的属性,这不太安全,但速度提高了一个数量级。因此,大多数其他 Underscore 函数的速度都有了小幅提升。Evgeniy Dolzhenko 贡献了_.tap类似于 Ruby 1.9 的,它方便将副作用(如日志记录)注入到链式调用中。

0.5.12009 年 12 月 9 日差异文档
恢复了 1.8.1 中更改的先前旧 Internet Explorer 和相关边缘情况行为。_.isArguments函数。许多小的安全检查和优化由 Noah SloanAndri Möll 贡献。

0.5.02009 年 12 月 7 日差异文档
[API 更改] 在用作迭代器时,对空数组返回现在将上下文对象作为其第一个参数。如果没有传递方法名称,则上下文对象的所有方法都绑定到它,从而启用链式调用和更轻松的绑定。_.functions现在接受一个参数并返回其函数属性的名称。调用_.functions(_)将获得以前的行为。添加了_.isRegExp,以便isEqual现在可以测试 RegExp 相等性。所有“is”函数都已缩减为一个定义。Karl Guertin 贡献了补丁。

0.4.72009 年 12 月 6 日差异文档
删除了isDate, isNaNsortedIndexisNull,为了完整性。对isEqual在检查数组或日期之间的相等性时的优化。样式的过滤,或采用函数作为自定义回调。现在速度提高了 25%–2 倍(取决于您的浏览器),这加快了依赖于它的函数的速度,例如样式的查找,采用对象以进行.

0.4.62009 年 11 月 30 日差异文档
,但仅适用于对象中的值。(真正的群众取悦者。)range函数,它是 同名 Python 函数 的移植版本,用于生成灵活编号的整数列表。原始补丁由 Kirill Ishanov 贡献。

0.4.52009 年 11 月 19 日差异文档
删除了rest用于数组和 arguments 对象,并为first添加了别名headsortedIndexrest添加了别名tail,这要感谢 Luke Sutton 的补丁。添加了测试,以确保所有 Underscore 数组函数也适用于 arguments 对象。

0.4.42009 年 11 月 18 日差异文档
删除了isStringsortedIndexisNumber,以保持一致性。修复了_.isEqual(NaN, NaN)以返回 true(这有争议)。

0.4.32009 年 11 月 9 日差异文档
开始在支持它的浏览器中使用本机StopIteration对象。修复了 CommonJS 环境的 Underscore 设置。

0.4.22009 年 11 月 9 日差异文档
将解包函数重命名为value,以便于理解。

0.4.12009 年 11 月 8 日差异文档
链式 Underscore 对象现在支持数组原型方法,因此您可以在包装的数组上执行所有操作,而无需中断链。添加了一个breakLoop方法,以便在任何 Underscore 迭代过程中中断。添加了一个isEmpty函数,该函数适用于数组和对象。

0.4.02009 年 11 月 7 日差异文档
所有 Underscore 函数现在都可以面向对象的方式调用,如下所示_([1, 2, 3]).map(...);。原始补丁由 Marc-André Cournoyer 提供。包装的对象可以通过多个方法调用进行链接。添加了一个 functions 方法,该方法提供 Underscore 中所有函数的排序列表。

0.3.32009 年 10 月 31 日差异文档
添加了 JavaScript 1.8 函数形式,它只复制“自身”属性。。将其别名为foldr,并将_.extend添加了别名foldl.

0.3.22009 年 10 月 29 日差异文档
现在可以使用load("underscore.js")在库存的 Rhino 解释器上运行。添加了 identity 作为实用函数。

0.3.12009 年 10 月 29 日差异文档
现在,所有迭代器都将原始集合作为其第三个参数传入,与 JavaScript 1.6 的 forEach 相同。现在使用(value, key, collection)调用对对象的迭代,有关详细信息,请参阅 _.each

0.3.02009年10月29日差异文档
添加了 Dmitry Baranovskiy 全面的优化,并入了 Kris Kowal 的补丁,使 Underscore 兼容 CommonJSNarwhal

0.2.02009年10月28日差异文档
删除了compose(组合)_.findIndex,重命名了inject(注入)_.extend,添加了别名inject(注入), every, countBy, rejectsortedIndex——一种不太有用的.

0.1.12009年10月28日差异文档
删除了noConflict(无冲突),以便可以将“Underscore”对象分配给其他变量。

0.1.02009年10月28日文档
Underscore.js 初始版本。

A DocumentCloud Project