underscore.js源码解析【数组】
// Array Functions
// --------------- // Get the first element of an array. Passing **n** will return the first N
// values in the array. Aliased as `head` and `take`. The **guard** check
// allows it to work with `_.map`.
/*
返回array(数组)的第一个元素。传递 n参数将返回数组中从第一个元素开始的n个元素
*/
_.first = _.head = _.take = function(array, n, guard) {
if (array == null || array.length < 1) return void 0;
if (n == null || guard) return array[0];
return _.initial(array, array.length - n);
}; // Returns everything but the last entry of the array. Especially useful on
// the arguments object. Passing **n** will return all the values in
// the array, excluding the last N.
/*
返回数组中除了最后一个元素外的其他全部元素。 在arguments对象上特别有用。传递 n参数将从结果中排除从最后一个开始的n个元素
*/
_.initial = function(array, n, guard) {
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
}; // Get the last element of an array. Passing **n** will return the last N
// values in the array.
/*
返回array(数组)的最后一个元素。传递 n参数将返回数组中从最后一个元素开始的n个元素
*/
_.last = function(array, n, guard) {
if (array == null || array.length < 1) return void 0;
if (n == null || guard) return array[array.length - 1];
return _.rest(array, Math.max(0, array.length - n));
}; // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
// Especially useful on the arguments object. Passing an **n** will return
// the rest N values in the array.
/*
返回数组中除了第一个元素外的其他全部元素。传递n参数将返回从n开始的剩余所有元素 。
*/
_.rest = _.tail = _.drop = function(array, n, guard) {
return slice.call(array, n == null || guard ? 1 : n);
}; // Trim out all falsy values from an array.
/*
返回一个除去所有false值的array副本。 在javascript中, false, null, 0, "", undefined 和 NaN 都是false值.
*/
_.compact = function(array) {
return _.filter(array, Boolean);
}; // Internal implementation of a recursive `flatten` function.
/*
内部的flatten函数
*/
var flatten = function(input, shallow, strict, output) {
output = output || [];
var idx = output.length;
for (var i = 0, length = getLength(input); i < length; i++) {
var value = input[i];
// 如果value还是数组或类数组
// _.isArguments(value)实现原理是判断value中是否有callee方法
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
// Flatten current level of array or arguments object.
//如果有shallow参数,则只打开一层
if (shallow) {
var j = 0, len = value.length;
while (j < len) output[idx++] = value[j++];
} else {// 否则,递归调用此函数,将结果数组output传入
flatten(value, shallow, strict, output);
idx = output.length;
}
} else if (!strict) {
output[idx++] = value;
}
}
return output;
}; // Flatten out an array, either recursively (by default), or just one level.
/*
将一个嵌套多层的数组 array(数组) (嵌套可以是任何层数)转换为只有一层的数组。 如果你传递 shallow参数,数组将只减少一维的嵌套。
*/
_.flatten = function(array, shallow) {
return flatten(array, shallow, false);
}; // Return a version of the array that does not contain the specified value(s).
/*
返回一个删除所有values值后的 array副本。
*/
_.without = restArgs(function(array, otherArrays) {
return _.difference(array, otherArrays);
}); // Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`.
/*
返回 array去重后的副本, 如果您确定 array 已经排序, 那么给 isSorted 参数传递 true值, 此函数将运行的更快的算法. 如果要处理对象元素, 传递 iteratee函数来获取要对比的属性
*/
_.uniq = _.unique = function(array, isSorted, iteratee, context) {
// 如果没有传递或传递的isSorted不为布尔值,后面两个参数前移
if (!_.isBoolean(isSorted)) {
context = iteratee;
iteratee = isSorted;
isSorted = false;
}
if (iteratee != null) iteratee = cb(iteratee, context);
var result = [];
var seen = [];// 表示已经有了的
for (var i = 0, length = getLength(array); i < length; i++) {// 遍历数组
var value = array[i],
computed = iteratee ? iteratee(value, i, array) : value;
if (isSorted) {// 如果数组已经是排序好的,只需判断前后两个值是否相等(效率高)
if (!i || seen !== computed) result.push(value);
seen = computed;
} else if (iteratee) {// 如果有iteratee函数,将值先push到seen中,再把value push到result中
if (!_.contains(seen, computed)) {
seen.push(computed);
result.push(value);
}
} else if (!_.contains(result, value)) {
result.push(value);
}
}
return result;
}; // Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
/*
返回传入的 arrays(数组)并集:按顺序返回,返回数组的元素是唯一的,可以传入一个或多个 arrays(数组)
*/
_.union = restArgs(function(arrays) {
return _.uniq(flatten(arrays, true, true));
}); // Produce an array that contains every item shared between all the
// passed-in arrays.
/*
返回传入 arrays(数组)交集。结果中的每个值是存在于传入的每个arrays(数组)里
这个函数的效率是数组长度的乘积
*/
_.intersection = function(array) {
var result = [];
var argsLength = arguments.length;
for (var i = 0, length = getLength(array); i < length; i++) {
var item = array[i];
if (_.contains(result, item)) continue;
var j;
for (j = 1; j < argsLength; j++) {
if (!_.contains(arguments[j], item)) break;
}
if (j === argsLength) result.push(item);
}
return result;
}; // Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
/*
类似于without,但返回的值来自array参数数组,并且不存在于other 数组
*/
_.difference = restArgs(function(array, rest) {
rest = flatten(rest, true, true);
return _.filter(array, function(value){
return !_.contains(rest, value);// 用indexOf() > 0来判断
});
}); // Complement of _.zip. Unzip accepts an array of arrays and groups
// each array's elements on shared indices.
/*
与zip功能相反的函数,给定若干arrays,返回一串联的新数组,其第一元素个包含所有的输入数组的第一元素,其第二包含了所有的第二元素,依此类推。
*/
_.unzip = function(array) {
var length = array && _.max(array, getLength).length || 0;// 返回数组中的元素的最长长度
var result = Array(length); for (var index = 0; index < length; index++) {
result[index] = _.pluck(array, index);// map(array, _.property(index))
}
return result;
}; // Zip together multiple lists into a single array -- elements that share
// an index go together.
/*
将 每个arrays中相应位置的值合并在一起。在合并分开保存的数据时很有用. 如果你用来处理矩阵嵌套数组时, _.zip.apply 可以做类似的效果。
*/
_.zip = restArgs(_.unzip); // Converts lists into objects. Pass either a single array of `[key, value]`
// pairs, or two parallel arrays of the same length -- one of keys, and one of
// the corresponding values.
/*
将数组转换为对象。传递任何一个单独[key, value]对的列表,或者一个键的列表和一个值得列表。 如果存在重复键,最后一个值将被返回。
*/
_.object = function(list, values) {
var result = {};
for (var i = 0, length = getLength(list); i < length; i++) {
if (values) {// 传入第二个参数
result[list[i]] = values[i];
} else {// 单独的[key,value]对
result[list[i][0]] = list[i][1];
}
}
return result;
}; // Generator function to create the findIndex and findLastIndex functions.
/*
遍历数组,找出符合predicate的项的index,找不到返回-1
*/
var createPredicateIndexFinder = function(dir) {
return function(array, predicate, context) {
predicate = cb(predicate, context);
var length = getLength(array);
var index = dir > 0 ? 0 : length - 1;
for (; index >= 0 && index < length; index += dir) {
if (predicate(array[index], index, array)) return index;
}
return -1;
};
}; // Returns the first index on an array-like that passes a predicate test.
/*
类似于_.indexOf
和_.findIndex类似,但反向迭代数组
*/
_.findIndex = createPredicateIndexFinder(1);
_.findLastIndex = createPredicateIndexFinder(-1); // Use a comparator function to figure out the smallest index at which
// an object should be inserted so as to maintain order. Uses binary search.
/*
使用二分查找确定value在list中的位置序号,value按此序号插入能保持list原有的排序。如果提供iterator函数,iterator将作为list排序的依据,包括你传递的value 。iterator也可以是字符串的属性名用来排序(比如length)。
*/
_.sortedIndex = function(array, obj, iteratee, context) {
iteratee = cb(iteratee, context, 1);
var value = iteratee(obj);
var low = 0, high = getLength(array);
while (low < high) {// 二分查找
var mid = Math.floor((low + high) / 2);
if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
}
return low;
}; // Generator function to create the indexOf and lastIndexOf functions.
/*
求元素在数组中的位置
*/
var createIndexFinder = function(dir, predicateFind, sortedIndex) {
return function(array, item, idx) {
var i = 0, length = getLength(array);
if (typeof idx == 'number') {// 如果传入了idx
if (dir > 0) {// 正向
i = idx >= 0 ? idx : Math.max(idx + length, i);
} else {// 反向
length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
}
} else if (sortedIndex && idx && length) {// 如果没传入,但是数组有序,直接调用sortedIndex(array, item)
idx = sortedIndex(array, item);
return array[idx] === item ? idx : -1;
}
if (item !== item) {// 如果item为NaN,说明要找出是NaN的元素
idx = predicateFind(slice.call(array, i, length), _.isNaN);
return idx >= 0 ? idx + i : -1;
}
for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
if (array[idx] === item) return idx;
}
return -1;
};
}; // Return the position of the first occurrence of an item in an array,
// or -1 if the item is not included in the array.
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
/*
返回value在该 array 中的索引值,如果value不存在 array中就返回-1。使用原生的indexOf 函数,除非它失效。如果您正在使用一个大数组,你知道数组已经排序,传递true给isSorted将更快的用二进制搜索..,或者,传递一个数字作为第三个参数,为了在给定的索引的数组中寻找第一个匹配值。
*/
_.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
_.lastIndexOf = createIndexFinder(-1, _.findLastIndex); // Generate an integer Array containing an arithmetic progression. A port of
// the native Python `range()` function. See
// [the Python documentation](http://docs.python.org/library/functions.html#range).
/*
一个用来创建整数灵活编号的列表的函数,便于each 和 map循环。如果省略start则默认为 0;step 默认为 1.返回一个从start 到stop的整数的列表,用step来增加 (或减少)独占。值得注意的是,如果stop值在start前面(也就是stop值小于start值),那么负增长。(这个地方中文文档的解释是错的)
*/
_.range = function(start, stop, step) {
if (stop == null) {
stop = start || 0;
start = 0;
}
if (!step) {
step = stop < start ? -1 : 1;
} var length = Math.max(Math.ceil((stop - start) / step), 0);
var range = Array(length); for (var idx = 0; idx < length; idx++, start += step) {
range[idx] = start;
} return range;
}; // Split an **array** into several arrays containing **count** or less elements
// of initial array.
/*
把数组arr从index=0处开始,分成长度为没有重复部分的长度小于count的数组所组成的数组
*/
_.chunk = function(array, count) {
if (count == null || count < 1) return []; var result = [];
var i = 0, length = array.length;
while (i < length) {
result.push(slice.call(array, i, i += count));// slice(s, e)方法当e大于数组最末尾位置时,返回从i到最后
}
return result;
};
underscore.js源码解析【数组】的更多相关文章
- underscore.js源码解析(五)—— 完结篇
		
最近公司各种上线,所以回家略感疲惫就懒得写了,这次我准备把剩下的所有方法全部分析完,可能篇幅过长...那么废话不多说让我们进入正题. 没看过前几篇的可以猛戳这里: underscore.js源码解析( ...
 - underscore.js源码解析(四)
		
没看过前几篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二) underscore.js源码解析(三) underscore.js源码GitHub地 ...
 - underscore.js源码解析(三)
		
最近工作比较忙,做不到每周两篇了,周末赶着写吧,上篇我针对一些方法进行了分析,今天继续. 没看过前两篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二 ...
 - underscore.js源码解析(二)
		
前几天我对underscore.js的整体结构做了分析,今天我将针对underscore封装的方法进行具体的分析,代码的一些解释都写在了注释里,那么废话不多说进入今天的正文. 没看过上一篇的可以猛戳这 ...
 - underscore.js源码解析(一)
		
一直想针对一个框架的源码好好的学习一下编程思想和技巧,提高一下自己的水平,但是看过一些框架的源码,都感觉看的莫名其妙,看不太懂,最后找到这个underscore.js由于这个比较简短,一千多行,而且读 ...
 - underscore.js源码解析【'_'对象定义及内部函数】
		
(function() { // Baseline setup // -------------- // Establish the root object, `window` (`self`) in ...
 - underscore.js源码解析【对象】
		
// Object Functions // ---------------- // Keys in IE < 9 that won't be iterated by `for key in . ...
 - underscore.js源码解析【函数】
		
// Function (ahem) Functions // ------------------ // Determines whether to execute a function as a ...
 - underscore.js源码解析【集合】
		
// Collection Functions // -------------------- // The cornerstone, an `each` implementation, aka `f ...
 
随机推荐
- sql-多表查询
			
一:外连接 1.左外连接(left join) select * from A left join B on A.id=B.a_id 结果如下 很明显,A表的所有数据都显示出来了 ...
 - http协议和四个层之间的关系
			
TCP/IP协议的分层:应用层.传输层.网络层.数据链路层. ····应用层···· 决定了向用户提供应用服务时通信的活动.HTTP协议存在于该层.(FTP文件传输协议,DNS域名系统) ....传输 ...
 - AJAX技术主要包含的四个组件
			
1.XMLHttpRequest:使用AJAX技术都是从XMLHttpRequest开始的. 2.JavaScript:实现XMLHttpRequest对象相关功能. 3.CSS 4.DOM
 - Jmeter小技巧以及问题集合
			
一.JDBC Request与BeanShell PostProcessor的结合使用 JDBCRequest部分 BeanShell PostProcessor配置项 二.if控制器的用法 三. ...
 - JAVA 8 主要新特性 ----------------(四)Lambda函数式接口
			
一.什么是函数式接口 只包含一个抽象方法的接口,称为函数式接口.  你可以通过 Lambda 表达式来创建该接口的对象.(若 Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法 ...
 - Day02  (黑客成长日记)
			
#用户登录次数为三代码 # i = 0 # while i < 3: # username = input('请输入账号:') # password = input('请输入密码:') # if ...
 - uasrt配置
			
Universal Synchronous/Asynchronous Receiver/Transmitter 同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式.同步要有一个 ...
 - java实现随机产生6位数的方法总结
			
package com.yin.test; import java.util.Random; import org.junit.Test; /** * @author v_yinyl * @date ...
 - EF6 学习笔记(二):操练 CRUD 增删改查
			
EF6学习笔记总目录 ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 接上篇: EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作 本篇原文链接: I ...
 - 21.ArrayList
			
ArrayList是实现List接口的动态数组,所谓动态就是它的大小是可变的.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类还提供一些方法来操作内部用来 ...