1. // Array Functions
  2. // ---------------
  3.  
  4. // Get the first element of an array. Passing **n** will return the first N
  5. // values in the array. Aliased as `head` and `take`. The **guard** check
  6. // allows it to work with `_.map`.
  7. /*
  8. 返回array(数组)的第一个元素。传递 n参数将返回数组中从第一个元素开始的n个元素
  9. */
  10. _.first = _.head = _.take = function(array, n, guard) {
  11. if (array == null || array.length < 1) return void 0;
  12. if (n == null || guard) return array[0];
  13. return _.initial(array, array.length - n);
  14. };
  15.  
  16. // Returns everything but the last entry of the array. Especially useful on
  17. // the arguments object. Passing **n** will return all the values in
  18. // the array, excluding the last N.
  19. /*
  20. 返回数组中除了最后一个元素外的其他全部元素。 在arguments对象上特别有用。传递 n参数将从结果中排除从最后一个开始的n个元素
  21. */
  22. _.initial = function(array, n, guard) {
  23. return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
  24. };
  25.  
  26. // Get the last element of an array. Passing **n** will return the last N
  27. // values in the array.
  28. /*
  29. 返回array(数组)的最后一个元素。传递 n参数将返回数组中从最后一个元素开始的n个元素
  30. */
  31. _.last = function(array, n, guard) {
  32. if (array == null || array.length < 1) return void 0;
  33. if (n == null || guard) return array[array.length - 1];
  34. return _.rest(array, Math.max(0, array.length - n));
  35. };
  36.  
  37. // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
  38. // Especially useful on the arguments object. Passing an **n** will return
  39. // the rest N values in the array.
  40. /*
  41. 返回数组中除了第一个元素外的其他全部元素。传递n参数将返回从n开始的剩余所有元素 。
  42. */
  43. _.rest = _.tail = _.drop = function(array, n, guard) {
  44. return slice.call(array, n == null || guard ? 1 : n);
  45. };
  46.  
  47. // Trim out all falsy values from an array.
  48. /*
  49. 返回一个除去所有false值的array副本。 在javascript中, false, null, 0, "", undefined 和 NaN 都是false值.
  50. */
  51. _.compact = function(array) {
  52. return _.filter(array, Boolean);
  53. };
  54.  
  55. // Internal implementation of a recursive `flatten` function.
  56. /*
  57. 内部的flatten函数
  58. */
  59. var flatten = function(input, shallow, strict, output) {
  60. output = output || [];
  61. var idx = output.length;
  62. for (var i = 0, length = getLength(input); i < length; i++) {
  63. var value = input[i];
  64. // 如果value还是数组或类数组
  65. // _.isArguments(value)实现原理是判断value中是否有callee方法
  66. if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
  67. // Flatten current level of array or arguments object.
  68. //如果有shallow参数,则只打开一层
  69. if (shallow) {
  70. var j = 0, len = value.length;
  71. while (j < len) output[idx++] = value[j++];
  72. } else {// 否则,递归调用此函数,将结果数组output传入
  73. flatten(value, shallow, strict, output);
  74. idx = output.length;
  75. }
  76. } else if (!strict) {
  77. output[idx++] = value;
  78. }
  79. }
  80. return output;
  81. };
  82.  
  83. // Flatten out an array, either recursively (by default), or just one level.
  84. /*
  85. 将一个嵌套多层的数组 array(数组) (嵌套可以是任何层数)转换为只有一层的数组。 如果你传递 shallow参数,数组将只减少一维的嵌套。
  86. */
  87. _.flatten = function(array, shallow) {
  88. return flatten(array, shallow, false);
  89. };
  90.  
  91. // Return a version of the array that does not contain the specified value(s).
  92. /*
  93. 返回一个删除所有values值后的 array副本。
  94. */
  95. _.without = restArgs(function(array, otherArrays) {
  96. return _.difference(array, otherArrays);
  97. });
  98.  
  99. // Produce a duplicate-free version of the array. If the array has already
  100. // been sorted, you have the option of using a faster algorithm.
  101. // Aliased as `unique`.
  102. /*
  103. 返回 array去重后的副本, 如果您确定 array 已经排序, 那么给 isSorted 参数传递 true值, 此函数将运行的更快的算法. 如果要处理对象元素, 传递 iteratee函数来获取要对比的属性
  104. */
  105. _.uniq = _.unique = function(array, isSorted, iteratee, context) {
  106. // 如果没有传递或传递的isSorted不为布尔值,后面两个参数前移
  107. if (!_.isBoolean(isSorted)) {
  108. context = iteratee;
  109. iteratee = isSorted;
  110. isSorted = false;
  111. }
  112. if (iteratee != null) iteratee = cb(iteratee, context);
  113. var result = [];
  114. var seen = [];// 表示已经有了的
  115. for (var i = 0, length = getLength(array); i < length; i++) {// 遍历数组
  116. var value = array[i],
  117. computed = iteratee ? iteratee(value, i, array) : value;
  118. if (isSorted) {// 如果数组已经是排序好的,只需判断前后两个值是否相等(效率高)
  119. if (!i || seen !== computed) result.push(value);
  120. seen = computed;
  121. } else if (iteratee) {// 如果有iteratee函数,将值先push到seen中,再把value push到result中
  122. if (!_.contains(seen, computed)) {
  123. seen.push(computed);
  124. result.push(value);
  125. }
  126. } else if (!_.contains(result, value)) {
  127. result.push(value);
  128. }
  129. }
  130. return result;
  131. };
  132.  
  133. // Produce an array that contains the union: each distinct element from all of
  134. // the passed-in arrays.
  135. /*
  136. 返回传入的 arrays(数组)并集:按顺序返回,返回数组的元素是唯一的,可以传入一个或多个 arrays(数组)
  137. */
  138. _.union = restArgs(function(arrays) {
  139. return _.uniq(flatten(arrays, true, true));
  140. });
  141.  
  142. // Produce an array that contains every item shared between all the
  143. // passed-in arrays.
  144. /*
  145. 返回传入 arrays(数组)交集。结果中的每个值是存在于传入的每个arrays(数组)里
  146. 这个函数的效率是数组长度的乘积
  147. */
  148. _.intersection = function(array) {
  149. var result = [];
  150. var argsLength = arguments.length;
  151. for (var i = 0, length = getLength(array); i < length; i++) {
  152. var item = array[i];
  153. if (_.contains(result, item)) continue;
  154. var j;
  155. for (j = 1; j < argsLength; j++) {
  156. if (!_.contains(arguments[j], item)) break;
  157. }
  158. if (j === argsLength) result.push(item);
  159. }
  160. return result;
  161. };
  162.  
  163. // Take the difference between one array and a number of other arrays.
  164. // Only the elements present in just the first array will remain.
  165. /*
  166. 类似于without,但返回的值来自array参数数组,并且不存在于other 数组
  167. */
  168. _.difference = restArgs(function(array, rest) {
  169. rest = flatten(rest, true, true);
  170. return _.filter(array, function(value){
  171. return !_.contains(rest, value);// 用indexOf() > 0来判断
  172. });
  173. });
  174.  
  175. // Complement of _.zip. Unzip accepts an array of arrays and groups
  176. // each array's elements on shared indices.
  177. /*
  178. 与zip功能相反的函数,给定若干arrays,返回一串联的新数组,其第一元素个包含所有的输入数组的第一元素,其第二包含了所有的第二元素,依此类推。
  179. */
  180. _.unzip = function(array) {
  181. var length = array && _.max(array, getLength).length || 0;// 返回数组中的元素的最长长度
  182. var result = Array(length);
  183.  
  184. for (var index = 0; index < length; index++) {
  185. result[index] = _.pluck(array, index);// map(array, _.property(index))
  186. }
  187. return result;
  188. };
  189.  
  190. // Zip together multiple lists into a single array -- elements that share
  191. // an index go together.
  192. /*
  193. 将 每个arrays中相应位置的值合并在一起。在合并分开保存的数据时很有用. 如果你用来处理矩阵嵌套数组时, _.zip.apply 可以做类似的效果。
  194. */
  195. _.zip = restArgs(_.unzip);
  196.  
  197. // Converts lists into objects. Pass either a single array of `[key, value]`
  198. // pairs, or two parallel arrays of the same length -- one of keys, and one of
  199. // the corresponding values.
  200. /*
  201. 将数组转换为对象。传递任何一个单独[key, value]对的列表,或者一个键的列表和一个值得列表。 如果存在重复键,最后一个值将被返回。
  202. */
  203. _.object = function(list, values) {
  204. var result = {};
  205. for (var i = 0, length = getLength(list); i < length; i++) {
  206. if (values) {// 传入第二个参数
  207. result[list[i]] = values[i];
  208. } else {// 单独的[key,value]对
  209. result[list[i][0]] = list[i][1];
  210. }
  211. }
  212. return result;
  213. };
  214.  
  215. // Generator function to create the findIndex and findLastIndex functions.
  216. /*
  217. 遍历数组,找出符合predicate的项的index,找不到返回-1
  218. */
  219. var createPredicateIndexFinder = function(dir) {
  220. return function(array, predicate, context) {
  221. predicate = cb(predicate, context);
  222. var length = getLength(array);
  223. var index = dir > 0 ? 0 : length - 1;
  224. for (; index >= 0 && index < length; index += dir) {
  225. if (predicate(array[index], index, array)) return index;
  226. }
  227. return -1;
  228. };
  229. };
  230.  
  231. // Returns the first index on an array-like that passes a predicate test.
  232. /*
  233. 类似于_.indexOf
  234. 和_.findIndex类似,但反向迭代数组
  235. */
  236. _.findIndex = createPredicateIndexFinder(1);
  237. _.findLastIndex = createPredicateIndexFinder(-1);
  238.  
  239. // Use a comparator function to figure out the smallest index at which
  240. // an object should be inserted so as to maintain order. Uses binary search.
  241. /*
  242. 使用二分查找确定value在list中的位置序号,value按此序号插入能保持list原有的排序。如果提供iterator函数,iterator将作为list排序的依据,包括你传递的value 。iterator也可以是字符串的属性名用来排序(比如length)。
  243. */
  244. _.sortedIndex = function(array, obj, iteratee, context) {
  245. iteratee = cb(iteratee, context, 1);
  246. var value = iteratee(obj);
  247. var low = 0, high = getLength(array);
  248. while (low < high) {// 二分查找
  249. var mid = Math.floor((low + high) / 2);
  250. if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
  251. }
  252. return low;
  253. };
  254.  
  255. // Generator function to create the indexOf and lastIndexOf functions.
  256. /*
  257. 求元素在数组中的位置
  258. */
  259. var createIndexFinder = function(dir, predicateFind, sortedIndex) {
  260. return function(array, item, idx) {
  261. var i = 0, length = getLength(array);
  262. if (typeof idx == 'number') {// 如果传入了idx
  263. if (dir > 0) {// 正向
  264. i = idx >= 0 ? idx : Math.max(idx + length, i);
  265. } else {// 反向
  266. length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
  267. }
  268. } else if (sortedIndex && idx && length) {// 如果没传入,但是数组有序,直接调用sortedIndex(array, item)
  269. idx = sortedIndex(array, item);
  270. return array[idx] === item ? idx : -1;
  271. }
  272. if (item !== item) {// 如果item为NaN,说明要找出是NaN的元素
  273. idx = predicateFind(slice.call(array, i, length), _.isNaN);
  274. return idx >= 0 ? idx + i : -1;
  275. }
  276. for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
  277. if (array[idx] === item) return idx;
  278. }
  279. return -1;
  280. };
  281. };
  282.  
  283. // Return the position of the first occurrence of an item in an array,
  284. // or -1 if the item is not included in the array.
  285. // If the array is large and already in sort order, pass `true`
  286. // for **isSorted** to use binary search.
  287. /*
  288. 返回value在该 array 中的索引值,如果value不存在 array中就返回-1。使用原生的indexOf 函数,除非它失效。如果您正在使用一个大数组,你知道数组已经排序,传递true给isSorted将更快的用二进制搜索..,或者,传递一个数字作为第三个参数,为了在给定的索引的数组中寻找第一个匹配值。
  289. */
  290. _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
  291. _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
  292.  
  293. // Generate an integer Array containing an arithmetic progression. A port of
  294. // the native Python `range()` function. See
  295. // [the Python documentation](http://docs.python.org/library/functions.html#range).
  296. /*
  297. 一个用来创建整数灵活编号的列表的函数,便于each 和 map循环。如果省略start则默认为 0;step 默认为 1.返回一个从start 到stop的整数的列表,用step来增加 (或减少)独占。值得注意的是,如果stop值在start前面(也就是stop值小于start值),那么负增长。(这个地方中文文档的解释是错的)
  298. */
  299. _.range = function(start, stop, step) {
  300. if (stop == null) {
  301. stop = start || 0;
  302. start = 0;
  303. }
  304. if (!step) {
  305. step = stop < start ? -1 : 1;
  306. }
  307.  
  308. var length = Math.max(Math.ceil((stop - start) / step), 0);
  309. var range = Array(length);
  310.  
  311. for (var idx = 0; idx < length; idx++, start += step) {
  312. range[idx] = start;
  313. }
  314.  
  315. return range;
  316. };
  317.  
  318. // Split an **array** into several arrays containing **count** or less elements
  319. // of initial array.
  320. /*
  321. 把数组arr从index=0处开始,分成长度为没有重复部分的长度小于count的数组所组成的数组
  322. */
  323. _.chunk = function(array, count) {
  324. if (count == null || count < 1) return [];
  325.  
  326. var result = [];
  327. var i = 0, length = array.length;
  328. while (i < length) {
  329. result.push(slice.call(array, i, i += count));// slice(s, e)方法当e大于数组最末尾位置时,返回从i到最后
  330. }
  331. return result;
  332. };

underscore.js源码解析【数组】的更多相关文章

  1. underscore.js源码解析(五)—— 完结篇

    最近公司各种上线,所以回家略感疲惫就懒得写了,这次我准备把剩下的所有方法全部分析完,可能篇幅过长...那么废话不多说让我们进入正题. 没看过前几篇的可以猛戳这里: underscore.js源码解析( ...

  2. underscore.js源码解析(四)

    没看过前几篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二) underscore.js源码解析(三) underscore.js源码GitHub地 ...

  3. underscore.js源码解析(三)

    最近工作比较忙,做不到每周两篇了,周末赶着写吧,上篇我针对一些方法进行了分析,今天继续. 没看过前两篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二 ...

  4. underscore.js源码解析(二)

    前几天我对underscore.js的整体结构做了分析,今天我将针对underscore封装的方法进行具体的分析,代码的一些解释都写在了注释里,那么废话不多说进入今天的正文. 没看过上一篇的可以猛戳这 ...

  5. underscore.js源码解析(一)

    一直想针对一个框架的源码好好的学习一下编程思想和技巧,提高一下自己的水平,但是看过一些框架的源码,都感觉看的莫名其妙,看不太懂,最后找到这个underscore.js由于这个比较简短,一千多行,而且读 ...

  6. underscore.js源码解析【'_'对象定义及内部函数】

    (function() { // Baseline setup // -------------- // Establish the root object, `window` (`self`) in ...

  7. underscore.js源码解析【对象】

    // Object Functions // ---------------- // Keys in IE < 9 that won't be iterated by `for key in . ...

  8. underscore.js源码解析【函数】

    // Function (ahem) Functions // ------------------ // Determines whether to execute a function as a ...

  9. underscore.js源码解析【集合】

    // Collection Functions // -------------------- // The cornerstone, an `each` implementation, aka `f ...

随机推荐

  1. Linux命令列内容

    命令列内容: 一般模式 移动光标 [ctrl]+[f] 屏幕[向前]移动一页 [ctrl]+[b] 屏幕[向后]移动一页 0 这是数字0:移动到这一行的最前面字符处 $ 移动到这一行的最后面字符处 G ...

  2. Shell 数值、字符串比较

    Shell脚本中,数值与字符串比较是不同的,因此要注意(注意[]括号内参数和括号之间有一个空格). 一.数值比较 -eq 等于,如: if [ $a -eq $b ] -ne    不等于,如: if ...

  3. 2018php最新面试题之PHP核心技术

    一.PHP核心技术 1.写出一个能创建多级目录的PHP函数(新浪网技术部) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php ...

  4. Spring 添加属性集中常见方法

    //创建容器,索要对象, package cn.lijun.Test; import org.junit.Test;import org.springframework.context.Applica ...

  5. gitlab 10安装

    电脑环境:centos6.2+gitlab10.0 gitlab10.0 (gitlab-ce-10.0.0-ce.0.el6.x86_64.rpm)下载地址:https://mirrors.tuna ...

  6. ScrollView嵌套Linearlayout显示不全的解决办法

    以为ScrollView只能嵌套一个元素,所以把几个控件都包裹在了一个LinearLayout中了.但是发现底部显示不全,滑动不到最底下. 代码: <ScrollView android:id= ...

  7. Linux环境部署项目引起Out of Memory Error: PermGen Space的解决方案

    1. 背景 前几天,在搭建项目时遇到到一些问题,现在整理记录一下. Linux环境:Red Hat Enterprise Linux Server release 6.4: # 查看命令cat /et ...

  8. MySQL DDL--ghost工具学习

    GHOST工作流程图: GHOST工作原理: .首先新建一张ghost表,结构与源表相同 .使用alter命令修改ghost表 3.1.模拟从库命令获取主库上该表的binlog(基于全镜像的行模式的b ...

  9. kaldi脚本注释二

    steps/decode.sh #!/bin/bash # Copyright 2012 Johns Hopkins University (Author: Daniel Povey) # Apach ...

  10. Delphi - 子窗体继承父窗体后如何显示父窗体上的控件

    1.创建子窗体Form1 File -> New -> Form,新建一个form,在form的单元文件中修改 2.子窗体中引用父窗体单元 uses TFatherForm 3.将子窗体中 ...