// Internal implementation of a recursive `flatten` function.
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];
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
// Flatten current level of array or arguments object.
if (shallow) {
var j = 0, len = value.length;
while (j < len) output[idx++] = value[j++];
} else {
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.
_.flatten = function(array, shallow) {
return flatten(array, shallow, false);
};
// Return a version of the array that does not contain the specified value(s).
_.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`.
_.uniq = _.unique = function(array, isSorted, iteratee, context) {
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) {
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.
_.union = restArgs(function(arrays) {
return _.uniq(flatten(arrays, true, true));
});
// Produce an array that contains every item shared between all the
// passed-in 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.
_.difference = restArgs(function(array, rest) {
rest = flatten(rest, true, true);
return _.filter(array, function(value){
return !_.contains(rest, value);
});
});
// Complement of _.zip. Unzip accepts an array of arrays and groups
// each array's elements on shared indices.
_.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);
}
return result;
};
// Zip together multiple lists into a single array -- elements that share
// an index go together.
_.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. Passing by pairs is the reverse of _.pairs.
_.object = function(list, values) {
var result = {};
for (var i = 0, length = getLength(list); i < length; i++) {
if (values) {
result[list[i]] = values[i];
} else {
result[list[i][0]] = list[i][1];
}
}
return result;
};
flatten
// Internal implementation of a recursive `flatten` function.
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];
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
// Flatten current level of array or arguments object.
if (shallow) {
var j = 0, len = value.length;
while (j < len) output[idx++] = value[j++];
} else {
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.
_.flatten = function(array, shallow) {
return flatten(array, shallow, false);
};
flatten函数铺平
网上搜着帮忙了
_.without
_.without = restArgs(function(array, otherArrays) {
return _.difference(array, otherArrays);
});
_.difference = restArgs(function(array, rest) {
rest = flatten(rest, true, true);
return _.filter(array, function(value){
return !_.contains(rest, value);
});
});
这个_.without
arguments[rest] ⇒ [[1,2], [1,3]]
会对otherarrays铺平一层数组吗然后一个个探测是否目标数组不具有对比数组元素,具有返回false,有返回true,最终返回符合条件的元素。
而_.difference则只是使用方式不同罢了
arguments[1] ⇒ [[1,2], [1,3]]
_.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 (!_.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); // 如果sorted了,则seen为单独的一个值
seen = computed;
} else if (iteratee) { //如果没有,则seen作为一个数组,每次必会被对照,而且value组也会跟sorted一样被对照,运算效率上会低一些
if (!_.contains(seen, computed)) {
seen.push(computed);
result.push(value);
}
} else if (!_.contains(result, value)) {
result.push(value);
}
}
return result; //返回结果
};
_.union
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = restArgs(function(arrays) {
return _.uniq(flatten(arrays, true, true));
});
参数名都叫arrays,应该夸名字起得好,作者的意思都不需要看代码了。
_.intersection
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
var result = []; //输出结果
var argsLength = arguments.length;
for (var i = 0, length = getLength(array); i < length; i++) {
var item = array[i]; // array是一个数组
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;
};
_.difference
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = restArgs(function(array, rest) {
rest = flatten(rest, true, true); // 先铺平rest
return _.filter(array, function(value){
return !_.contains(rest, value);
}); // 再筛选出值
});
_.unzip
// Complement of _.zip. Unzip accepts an array of arrays and groups
// each array's elements on shared indices.
_.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); // 取每个数组的0,1,2,3.......属性并进行归类
}
return result;
};
_.zip
_.zip = restArgs(_.unzip);
我们再回顾一下restArg函数
var restArgs = function(func, startIndex) {
startIndex = startIndex == null ? func.length - 1 : +startIndex;
return function() {
var length = Math.max(arguments.length - startIndex, 0),
rest = Array(length),
index = 0;
for (; index < length; index++) {
rest[index] = arguments[index + startIndex];
}
switch (startIndex) {
case 0: return func.call(this, rest);
case 1: return func.call(this, arguments[0], rest);
case 2: return func.call(this, arguments[0], arguments[1], rest);
}
var args = Array(startIndex + 1);
for (index = 0; index < startIndex; index++) {
args[index] = arguments[index];
}
args[startIndex] = rest;
return func.apply(this, args);
};
};
我们发现,当我们传入unzip的结果,也就是在arguments中传数组的时候,unzip就会将array默认为rest param,进行处理,也就是说,比如我们传入了以0分组的数组,当我们匹配了第一个数组的array[0],即原本第一个数组的第一个数array[0]时则其会相应匹配array[1]分组中的第一个,即原本第一个数组的array[1],这样就又达到了合并数据的效果, 非常巧妙。
_.object
// 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. Passing by pairs is the reverse of _.pairs.
_.object = function(list, values) {
var result = {};
for (var i = 0, length = getLength(list); i < length; i++) {
if (values) {
result[list[i]] = values[i];
} else {
result[list[i][0]] = list[i][1];
}
}
return result;
};
以上一个例子就可以明白这个想做什么了
_.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}
没了