// Collection Functions
// -------------------- // The cornerstone, an `each` implementation, aka `forEach`.
// Handles raw objects in addition to array-likes. Treats all
// sparse array-likes as if they were dense.
/*
params: 数组、对象或类数组对象,函数,函数执行环境
*/
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context);
var i, length;
if (isArrayLike(obj)) {// 数组或类数组
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);// item index obj
}
} else {// 对象
var keys = _.keys(obj);// 返回键的数组
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
}; // Return the results of applying the iteratee to each element.
/*
通过转换函数(iteratee迭代器)映射列表中的每个值产生价值的新数组
这个函数很简洁的处理类数组与对象的不同情况,值得学习!!!!!!!!!!!!!!!!!!!
*/
_.map = _.collect = function(obj, iteratee, context) {
iteratee = cb(iteratee, context);
var keys = !isArrayLike(obj) && _.keys(obj),//如果是数组,返回false;否则返回对象的keys数组
length = (keys || obj).length,
results = Array(length);
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;// 如果是对象,返回key; 数组返回index
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
}; // Create a reducing function iterating left or right.
/*
创建迭代
params:方向(-1为左,1为右)
*/
var createReduce = function(dir) {
// Wrap code that reassigns argument variables in a separate function than
// the one that accesses `arguments.length` to avoid a perf hit. (#1991)
/*
params: obj,执行函数,起始值,起始值和context
*/
var reducer = function(obj, iteratee, memo, initial) {
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
index = dir > 0 ? 0 : length - 1;
if (!initial) {// 如果没有起始值这个参数
memo = obj[keys ? keys[index] : index];
index += dir;
}
for (; index >= 0 && index < length; index += dir) {
var currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
}; return function(obj, iteratee, memo, context) {
var initial = arguments.length >= 3;
return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
};
}; // **Reduce** builds up a single result from a list of values, aka `inject`,
// or `foldl`.
_.reduce = _.foldl = _.inject = createReduce(1); // The right-associative version of reduce, also known as `foldr`.
_.reduceRight = _.foldr = createReduce(-1); // Return the first value which passes a truth test. Aliased as `detect`.
/*
在list中逐项查找,返回第一个通过predicate迭代函数真值检测的元素值,如果没有值传递给测试迭代器将返回
*/
_.find = _.detect = function(obj, predicate, context) {
var keyFinder = isArrayLike(obj) ? _.findIndex : _.findKey;
var key = keyFinder(obj, predicate, context);
if (key !== void 0 && key !== -1) return obj[key];
}; // Return all the elements that pass a truth test.
// Aliased as `select`.
/*
遍历list中的每个值,返回包含所有通过predicate真值检测的元素值
与原生的filter函数作用相同,有原生的时候可以使用原生的filter
*/
_.filter = _.select = function(obj, predicate, context) {
var results = [];
predicate = cb(predicate, context);
_.each(obj, function(value, index, list) {//遍历所有元素,返回符合条件的value
if (predicate(value, index, list)) results.push(value);
});
return results;
}; // Return all the elements for which a truth test fails.
/*
返回list中没有通过predicate真值检测的元素集合,与filter相反
*/
_.reject = function(obj, predicate, context) {
return _.filter(obj, _.negate(cb(predicate)), context);
}; // Determine whether all of the elements match a truth test.
// Aliased as `all`.
/*
如果list中的所有元素都通过predicate的真值检测就返回true
与原生的every函数作用相同,有原生的时候可以使用原生的every
*/
_.every = _.all = function(obj, predicate, context) {
predicate = cb(predicate, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length;
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
if (!predicate(obj[currentKey], currentKey, obj)) return false;//如果找到一个不符合,直接中断函数
}
return true;
}; // Determine if at least one element in the object matches a truth test.
// Aliased as `any`.
/*
如果list中有任何一个元素通过 predicate 的真值检测就返回true。一旦找到了符合条件的元素, 就直接中断对list的遍历
*/
_.some = _.any = function(obj, predicate, context) {
predicate = cb(predicate, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length;
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
if (predicate(obj[currentKey], currentKey, obj)) return true;
}
return false;
}; // Determine if the array or object contains a given item (using `===`).
// Aliased as `includes` and `include`.
/*
如果list包含指定的value则返回true
*/
_.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
if (!isArrayLike(obj)) obj = _.values(obj);//将对象中所有value压入一个数组
if (typeof fromIndex != 'number' || guard) fromIndex = 0;
return _.indexOf(obj, item, fromIndex) >= 0;
}; // Invoke a method (with arguments) on every item in a collection.
/*
在list的每个元素上执行methodName方法
*/
_.invoke = restArgs(function(obj, method, args) {// 将多余三个之外的参数合并为一个数组传入到参数函数中
var isFunc = _.isFunction(method);
return _.map(obj, function(value) {
var func = isFunc ? method : value[method];
return func == null ? func : func.apply(value, args);
});
}); // Convenience version of a common use case of `map`: fetching a property.
_.pluck = function(obj, key) {
return _.map(obj, _.property(key));//property() 返回获取obj[key]的函数
}; // Convenience version of a common use case of `filter`: selecting only objects
// containing specific `key:value` pairs.
/*
遍历list中的每一个值,返回一个数组,这个数组包含properties所列出的属性的所有的 键 - 值对
*/
_.where = function(obj, attrs) {
return _.filter(obj, _.matcher(attrs));
}; /*
遍历整个list,返回匹配 properties参数所列出的所有 键 - 值 对的第一个值。
*/
// Convenience version of a common use case of `find`: getting the first object
// containing specific `key:value` pairs.
_.findWhere = function(obj, attrs) {
return _.find(obj, _.matcher(attrs));
}; // Return the maximum element (or element-based computation).
/*
返回list中的最大值。如果传递iteratee参数,iteratee将作为list中每个值的排序依据。如果list为空,将返回-Infinity
*/
_.max = function(obj, iteratee, context) {
var result = -Infinity, lastComputed = -Infinity,
value, computed;
if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) {
// 不存在iteratee参数,或者iteratee为数字类型m,obj[0]是object类型??????????????????????????????????????????
obj = isArrayLike(obj) ? obj : _.values(obj);// 判断obj是不是数组或类数组(有没有正确类型的length)
for (var i = 0, length = obj.length; i < length; i++) {
value = obj[i];
if (value != null && value > result) {
result = value;
}
}
} else {
// 存在iteratee参数
iteratee = cb(iteratee, context);
// 利用each对整个数组进行操作
_.each(obj, function(v, index, list) {
computed = iteratee(v, index, list);
if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
result = v;
lastComputed = computed;
}
});
}
return result;
}; // Return the minimum element (or element-based computation).
/*
返回list中的最小值。如果传递iteratee参数,iteratee将作为list中每个值的排序依据。如果list为空,将返回-Infinity
实现与上述一致
*/
_.min = function(obj, iteratee, context) {
var result = Infinity, lastComputed = Infinity,
value, computed;
if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) {
obj = isArrayLike(obj) ? obj : _.values(obj);
for (var i = 0, length = obj.length; i < length; i++) {
value = obj[i];
if (value != null && value < result) {
result = value;
}
}
} else {
iteratee = cb(iteratee, context);
_.each(obj, function(v, index, list) {
computed = iteratee(v, index, list);
if (computed < lastComputed || computed === Infinity && result === Infinity) {
result = v;
lastComputed = computed;
}
});
}
return result;
}; // Shuffle a collection.
/*
返回一个随机乱序的 list 副本, 使用 Fisher-Yates shuffle 来进行随机乱序
*/
_.shuffle = function(obj) {
return _.sample(obj, Infinity);
}; // Sample **n** random values from a collection using the modern version of the
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
// If **n** is not specified, returns a single random element.
// The internal `guard` argument allows it to work with `map`.
/*
从 list中产生一个随机样本。传递一个数字表示从list中返回n个随机元素。否则将返回一个单一的随机项
*/
_.sample = function(obj, n, guard) {
if (n == null || guard) {// 没传递n或者是传递了guard参数
if (!isArrayLike(obj)) obj = _.values(obj);
return obj[_.random(obj.length - 1)];// _.random()利用Math.random返回随机数组下标的值
}
var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj);
var length = getLength(sample);
n = Math.max(Math.min(n, length), 0);// 取n和length的最小值
var last = length - 1;
// 选出数量为n的随机数
// 这里不用arr.sort()方法是因为利用数组排序进行随机排列会有分布不均的现象,具体见https://www.h5jun.com/post/array-shuffle.html
for (var index = 0; index < n; index++) {
var rand = _.random(index, last);
var temp = sample[index];
sample[index] = sample[rand];
sample[rand] = temp;
}
return sample.slice(0, n);
}; // Sort the object's values by a criterion produced by an iteratee.
/*
返回一个排序后的list拷贝副本。如果传递iteratee参数,iteratee将作为list中每个值的排序依据。
*/
_.sortBy = function(obj, iteratee, context) {
var index = 0;
iteratee = cb(iteratee, context);
// _.pluck()返回对象数组中所有对象的value属性组成的数组
return _.pluck(_.map(obj, function(value, key, list) {// 把数组中每个值包装成一个对象,返回一个对象数组
return {
value: value,
index: index++,
criteria: iteratee(value, key, list)
};
}).sort(function(left, right) {// 数组中的值按照函数执行结果或字符串进行排序
var a = left.criteria;
var b = right.criteria;
if (a !== b) {
if (a > b || a === void 0) return 1;
if (a < b || b === void 0) return -1;
}
return left.index - right.index;
}), 'value');
}; // An internal function used for aggregate "group by" operations.
/*
params: 执行函数,是否分成两份????????????????????????????
*/
var group = function(behavior, partition) {
// 返回一个接受三个参数的函数
// 对传入数组每一项执行iteratee并将结果传入behavior执行
return function(obj, iteratee, context) {
var result = partition ? [[], []] : {};
iteratee = cb(iteratee, context);
_.each(obj, function(value, index) {
var new_val = iteratee(value, index, obj);// 这里参数名称改为new_val感觉更好理解一点
behavior(result, value, new_val);
});
return result;
};
}; // Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
/*
把一个集合分组为多个集合,通过 iterator 返回的结果进行分组. 如果 iterator 是一个字符串而不是函数, 那么将使用 iterator 作为各元素的属性名来对比进行分组
params: [[], []]或{},每一项的value与对应iteratee(value, index, obj)的结果
*/
_.groupBy = group(function(result, value, key) {
if (_.has(result, key)) result[key].push(value); else result[key] = [value];// 如果result中已经有了key属性,则push(value);否则新增属性key
}); // Indexes the object's values by a criterion, similar to `groupBy`, but for
// when you know that your index values will be unique.
/*
给定一个list,和 一个用来返回一个在列表中的每个元素键 的iterator 函数(或属性名), 返回一个每一项索引的对象。
*/
_.indexBy = group(function(result, value, key) {
result[key] = value;
}); // Counts instances of an object that group by a certain criterion. Pass
// either a string attribute to count by, or a function that returns the
// criterion.
/*
排序一个列表组成一个组,并且返回各组中的对象的数量的计数。
类似groupBy,但是不是返回列表的值,而是返回在该组中值的数目。
*/
_.countBy = group(function(result, value, key) {
if (_.has(result, key)) result[key]++; else result[key] = 1;
}); /*
第一个表示不包含代理对代码点的所有字符
第二个表示合法的代理对的所有字符
第三个表示代理对的代码点(本身不是合法的Unicode字符)
意思就是所有字符,'hello'.match(reStrSymbol); ==> ['h','e','l','l','o']
*/
var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;
// Safely create a real, live array from anything iterable.
/*
把obj(任何可以迭代的对象)转换成一个数组,在转换 arguments 对象时非常有用
*/
_.toArray = function(obj) {
if (!obj) return [];
if (_.isArray(obj)) return slice.call(obj);// 如果是纯数组,直接用slice.call()
if (_.isString(obj)) {//如果是字符串
// Keep surrogate pair characters together
return obj.match(reStrSymbol);
}
if (isArrayLike(obj)) return _.map(obj, _.identity);// 如果是对象类似于_.kets(obj)
return _.values(obj);
}; // Return the number of elements in an object.
/*
返回list的长度。
*/
_.size = function(obj) {
if (obj == null) return 0;
return isArrayLike(obj) ? obj.length : _.keys(obj).length;
}; // Split a collection into two arrays: one whose elements all satisfy the given
// predicate, and one whose elements all do not satisfy the predicate.
/*
拆分一个数组(array)为两个数组: 第一个数组其元素都满足predicate迭代函数, 而第二个的所有元素均不能满足predicate迭代函数。
pass为传入迭代函数的返回值
*/
_.partition = group(function(result, value, pass) {
result[pass ? 0 : 1].push(value);
}, true);

小结

1.处理类数组与对象的不同情况

var keys = !isArrayLike(obj) && _.keys(obj),//如果是数组,返回false;否则返回对象的keys数组
length = (keys || obj).length,
results = Array(length);

2.高阶函数的使用

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

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

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

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

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

  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源码解析【数组】

    // Array Functions // --------------- // Get the first element of an array. Passing **n** will retur ...

随机推荐

  1. php面试题五之nginx如何调用php和php-fpm的作用和工作原理

    nginx如何调用php 采用nginx+php作为webserver的架构模式,在现如今运用相当广泛.然而第一步需要实现的是如何让nginx正确的调用php.由于nginx调用php并不是如同调用一 ...

  2. Python基础-python数据类型之列表(四)

    列表 格式 namesList = [ 字符串,数字,列表,元祖,集合] 列表中的元素可以是不 同类型的 列表的相关操作 列表中存放的数据是可以进行修改的,比如"增"." ...

  3. Java16-java语法基础——异常

    Java16-java语法基础——异常 一.异常概念 1.异常:应用程序在运行过程中出现的错误或非正常的意外情况,即虚拟机的通常操作中可能遇到的异常,是一种常见的运行错误. 2.原因:数组越界.空指针 ...

  4. [原]OpenStreetMap数据瓦片服务性能篇

    上文说到如何利用node-mapnik架设OpenStreetMap瓦片服务,解决了有没有的问题.然而这个服务还是比较孱弱,主要表现在以下几个方面: 1. Node.js只能使用CPU的一个核,不能有 ...

  5. MySQL数据查询之多表查询

    多表查询 多表联合查询 #创建部门 CREATE TABLE IF NOT EXISTS dept ( did int not null auto_increment PRIMARY KEY, dna ...

  6. 基于UML的中职班主任工作管理系统的分析与设计--文献随笔(二)

    一.基本信息 标题:基于UML的中职班主任工作管理系统的分析与设计 时间:2016 出版源:遵义航天工业学校 关键字:中职学校; 班主任工作管理; UML建模 二.研究背景 问题定义:班主任是一项特殊 ...

  7. Pivot For和UNPivot For

    一.使用PIVOT和UNPIVOT命令的SQL Server版本要求 1.数据库的最低版本要求为SQL Server 2005 或更高. 2.必须将数据库的兼容级别设置为90 或更高. 3.查看我的数 ...

  8. adb Android Debug Bridge 安卓调试桥

    adb devices 获取设备列表及设备状态 adb get-state 获取设备的状态,设备的状态有 3 钟,device , offline , unknown device:设备正常连接 of ...

  9. [.net core学习] .net core中的MD5CryptoServiceProvider取代方法

    使用:MD5 m5 = MD5.Create(); 参考:http://stackoverflow.com/questions/27216121/alternatives-of-md5cryptose ...

  10. 使用netstat命令查看端口的使用情况

    Windows如何查看端口占用情况操作步骤如下: 开始--运行--cmd 进入命令提示符,输入netstat -ano 即可看到所有连接的PID 之后在任务管理器中找到这个PID所对应的程序如果任务管 ...