// Array Functions
// ---------------
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* first
* 返回第一个元素 或者从第一个元素开始到第n个元素
*/
// 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`.
_.first = _.head = _.take = function(array, n, guard) {
// 如果array 不存在 则返回undefined
if (array == null) return void 0;
// 如果n不存在,则返回第一个
if (n == null || guard) return array[0];
// 否则返回第1个到n 使用了_.initial(), 把后面不要的扔掉正好是需要的
return _.initial(array, array.length - n);
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* initial
* 返回数组中除了最后一个元素外的其他全部元素。如果有n ,就把后面n个就干掉了
* 意思就是干掉后面多少个,类似pop,只不过可以干掉多个
*/
// 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.
_.initial = function(array, n, guard) {
// 拆分array, 从第0个拆分到指定位置 ,n 把后面n个就干掉了
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* last
* 和first相反,返回最后一个,或者后面n个
*/
// Get the last element of an array. Passing **n** will return the last N
// values in the array.
_.last = function(array, n, guard) {
if (array == null) return void 0;
if (n == null || guard) return array[array.length - 1];
// _.rest() 没有参数n则返回最后一个,否则返回length-n 到最后一个
return _.rest(array, Math.max(0, array.length - n));
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* rest
* 从已有数组中返回指定字符串,原生方法
*/
// 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.
_.rest = _.tail = _.drop = function(array, n, guard) {
return slice.call(array, n == null || guard ? 1 : n);
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* compact
* 返回一个除去所有false值的 array副本。
*/
// Trim out all falsy values from an array.
// 因为_.identity返回的就是本身,而filter返回的是所有真值,所以会返回一个除去所有false值的 array副本。
// 在javascript中, false, null, 0, "", undefined 和 NaN 都是false值.
_.compact = function(array) {
return _.filter(array, _.identity);
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* flatten
* 将嵌套数组扁平化,如果shallow为true,则只铺平一层
*/
// Internal implementation of a recursive `flatten` function.
var flatten = function(input, shallow, strict, startIndex) {
var output = [], idx = 0;
for (var i = startIndex || 0, length = input && input.length; i < length; i++) {
var value = input[i];
// 处理如果input[i],仍然是数组的情况 , else ,直接添加
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
// 扁平当前级别的数组或参数对象,使用递归,每次循环value,将里面的数组调用并平铺
// flatten current level of array or arguments object
if (!shallow) value = flatten(value, shallow, strict);
var j = 0, len = value.length;
output.length += len;
// index++ 每次添加一个子集j++的元素
// 循环子元素,把每一个都添加到父集
while (j < len) {
output[idx++] = value[j++];
}
} else if (!strict) {
output[idx++] = value;
}
}
return output;
};
// Flatten out an array, either recursively (by default), or just one level.
_.flatten = function(array, shallow) {
// 这里第三个参数是为了兼容其他的函数,
return flatten(array, shallow, false);
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* without
* 返回第一个数组不包含后面参数的值
* 和difference差不多,只不过把后面的数组变成了参数
*/
// Return a version of the array that does not contain the specified value(s).
_.without = function(array) {
// _.difference(array1,array2) 返回array1不存在array2中的值。
// slice.call(arguments, 1), -> 返回所有参数除去第一个之后的一个数组
return _.difference(array, slice.call(arguments, 1));
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* uniq & unique
* 去重
*/
// 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`.
_.uniq = _.unique = function(array, isSorted, iteratee, context) {
if (array == null) return [];
// 第二个值必须是布尔值,否则为false,也就是不需要后面自定义排序方法
if (!_.isBoolean(isSorted)) {
context = iteratee;
iteratee = isSorted;
isSorted = false;
}
// 这是处理一个对象的方法,获取对比的属性
if (iteratee != null) iteratee = cb(iteratee, context);
var result = [];
var seen = [];
// 循环array中的每一项
for (var i = 0, length = array.length; i < length; i++) {
// 获取每一项的值,与比较的方式
var value = array[i],
computed = iteratee ? iteratee(value, i, array) : value;
// 如果需要自定义处理,则isSorted为true
if (isSorted) {
// 如果i = 0,则 !i = true
// 如果后面一个值不等于前面一个值,则push,因为已经排序,所以数组类似[1, 1, 3, 5, 5, 6, 6,
6, 7]
// 所以只要后一个不同于前一个,就push否则跳过就好
if (!i || seen !== computed) result.push(value);
seen = computed;
} else if (iteratee) {
// 是否有条件判断语句
if (!.contains(seen, computed)) {
seen.push(computed);
result.push(value);
}
// 比较数组.contains(),会返回一个是否包含第二个参数的布尔值
// 如果不包含,则push
} else if (!_.contains(result, value)) {
result.push(value);
}
}
return result;
};
_.uniq(array, [isSorted], [iteratee]);
// array -> 需要处理的数组,
// isSorted -> 是否已经排序
// iteratee -> 是否自定义排序规则
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* union
* 提取并集
*/
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
// arguments首先将参数合并为数组,
// flatten 再将数组扁平化
// 最后使用_.uniq()对数组去重
return _.uniq(flatten(arguments, true, true));
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* intersection
* 提取交际
*/
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
if (array == null) return [];
var result = [];
var argsLength = arguments.length;
// 循环第一个arrray,结果肯定在第一个array中存在
for (var i = 0, length = array.length; i < length; i++) {
var item = array[i];
// 如果item在result中存在,则跳出本次循环
if (_.contains(result, item)) continue;
// 检查第一个array的item 是否在每一个总都存在,否则退出
for (var j = 1; j < argsLength; j++) {
if (!_.contains(arguments[j], item)) break;
}
// 如果每个都存在,就保存
// j === argsLength 意思是为了确保上面的循环跑完了。
if (j === argsLength) result.push(item);
}
return result;
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* intersection
* 类似于without,但返回的值来自array参数数组,并且不存在于other 数组.
*/
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = function(array) {
// 现将所有数组扁平化,后面的1值不包含第一个array
var rest = flatten(arguments, true, true, 1);
// 然后取出所有真值
return _.filter(array, function(value){
// _.contains() 本位比较真值,取反则为假
return !_.contains(rest, value);
});
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* zip & unzip
* 两个差不多,都是讲对应位置的值放在一起,只不过zip是将全部数组放在一个数组中,二unzip是将他们分开成多个
*/
// Zip together multiple lists into a single array -- elements that share
// an index go together.
_.zip = function() {
return _.unzip(arguments);
};
// Complement of _.zip. Unzip accepts an array of arrays and groups
// each array's elements on shared indices
_.unzip = function(array) {
// 兼容具有length属性的对象
var length = array && _.max(array, 'length').length || 0;
var result = Array(length);
for (var index = 0; index < length; index++) {
// _.pluck(array, key),返回所有数组中包含key值的value
result[index] = _.pluck(array, index);
}
return result;
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* object
* 将键值对数组转换为json,或者将两个数组,对应index的值转为json
* 有values值 ,则([a, b, c], [1, 2, 3]) -> {a: 1, b: 2, c: 3}
* 没有则: ([[a, 2], [b, 2], [c, 3]) -> {a: 1, b: 2, c: 3}
*/
// 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.
_.object = function(list, values) {
var result = {};
for (var i = 0, length = list && list.length; i < length; i++) {
if (values) {
// 如果有values则匹配相同的index
result[list[i]] = values[i];
} else {
// 如果只有一个参数,则匹配二维数组的第一个值个第二个值
result[list[i][0]] = list[i][1];
}
}
return result;
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* indexOf & lastIndexOf
* 查找索引
*/
// 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.
_.indexOf = function(array, item, isSorted) {
var i = 0, length = array && array.length;
if (typeof isSorted == 'number') {
// 正: 则为本身,负: 则减去它
i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
} else if (isSorted && length) {
// _.sortedIndex(array, item); 将item插入array,能保障排序, i标示插入的索引
// 其实就是把他插入本来应该在的位置,但是比较的时候却没有,所以就是-1
i = _.sortedIndex(array, item);
return array[i] === item ? i : -1;
}
// 如果是NaN ,findIndex寻找NaN的位置 -> 数字一定要判断NaN的情况
if (item !== item) {
return _.findIndex(slice.call(array, i), _.isNaN);
}
for (; i < length; i++) if (array[i] === item) return i;
return -1;
};
_.lastIndexOf = function(array, item, from) {
var idx = array ? array.length : 0;
// idx不能大于length-1
if (typeof from == 'number') {
idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
}
// NaN
if (item !== item) {
return _.findLastIndex(slice.call(array, 0, idx), _.isNaN);
}
// --idx = length-1 ,如果有一个相等,则输出,否则返回 -1
while (--idx >= 0) if (array[idx] === item) return idx;
return -1;
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* findIndex & findLastIndex
* 类似于_.indexOf ,只不过indexOf给的是元素,而这个需要表达式
*/
// Generator function to create the findIndex and findLastIndex functions
function createIndexFinder(dir) {
return function(array, predicate, context) {
predicate = cb(predicate, context);
var length = array != null && array.length;
var index = dir > 0 ? 0 : length - 1;
for (; index >= 0 && index < length; index += dir) {
// 如果回调函数为true,则输出index
if (predicate(array[index], index, array)) return index;
}
return -1;
};
}
// Returns the first index on an array-like that passes a predicate test
_.findIndex = createIndexFinder(1);
_.findLastIndex = createIndexFinder(-1);
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* sortedIndex
* 使用二分查找确定value在list中的位置序号
*/
// 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.
_.sortedIndex = function(array, obj, iteratee, context) {
// 检查iteratee是否存在,是否为对象
iteratee = cb(iteratee, context, 1);
var value = iteratee(obj);
var low = 0, high = array.length;
// 每一次都拿中间值与目标比较,mid+ 1 取后部分,或者high = mid 取前部分,以此类推
while (low < high) {
var mid = Math.floor((low + high) / 2);
if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
}
return low;
};
/*—————————————————————————————————————————————————————————
—————————————————*/
/**
* range
* 一个用来创建整数灵活编号的列表的函数
*/
// 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).
_.range = function(start, stop, step) {
if (arguments.length <= 1) {
stop = start || 0;
start = 0;
}
step = step || 1;
// ceil 向上取整
// 创建数组及计算数组个数
var length = Math.max(Math.ceil((stop - start) / step), 0);
var range = Array(length);
// start 每次都加 step
for (var idx = 0; idx < length; idx++, start += step) {
range[idx] = start;
}
return range;
};