V-1.8.2 underscore源码解析(三)
来源:互联网 发布:js use strict 编辑:程序博客网 时间:2024/06/06 03:14
V-1.8.2 underscore源码解析(三)
// each的实现类似于forEach
// 遍历数组或对象的每个元素。第一个参数为数组(类数组)或对象
// 第二个参数为迭代方法,对数组或对象每个元素执行该方法,
// 第三个参数(可省略)来决定iteratee的this指向
_.each = _.forEach = function(obj, iteratee, context) { // 如果包含context参数,this指向context,将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); } // 如果是对象,获取对象所有的value(obj[keys[i]])的值 } else { var keys = _.keys(obj); // 遍历处理values的值 for(i = 0, length = keys.length; i < length; i++) { // 迭代当前索引的值(value),索引(key),当前数组或对象 iteratee(obj[keys[i]], keys[i], obj); } } // 返回传入的obj参数,以方便链式调用 return obj; };
var arr1 = {one:'zha',two:'chg',three:'bai'};var arr2 = [1,2,3];var obj = _.each(arr1,function(value,key,arr1){ console.log('key值为 '+key+' value值为 '+value +' list参数为 '+ arr1); })console.log('obj的值 ' + obj);var obj2 = _.each(arr2,function(value,key,list){ console.log('key值为 '+key+' value值为 '+value +' list参数为 '+ list); })console.log( 'obj2的值为 '+obj2);
//map方法通过转换函数(迭代器函数)映射列表中的每个值产生价值的新数组
//iteratee包含三个参数:value,key(index),最后一个是引用指向整个list
_.map = _.collect = function(obj, iteratee, context) {// 如果有context参数,就将迭代方法绑定到context上下文,确定this指向 iteratee = cb(iteratee, context);// 如果传参是个对象,获取他的keys值数组// 获取类数组或者对象的长度// 创建一个新的确定长度的数组 var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, results = Array(length);// 判断keys是否可枚举,即是否为对象,是就返回keys[index](value值),currentKey为对象的key值// 若不为对象,为数组,则currentKey为数组的下标 for(var index = 0; index < length; index++) { var currentKey = keys ? keys[index] : index;// 重组新的数组 results[index] = iteratee(obj[curentKey], currentKey, obj); }// 返回新的结果数组 return result; };
// Create a reducing function iterating left or right.
//创建一个向左或向右迭代方向的归纳函数
// memo为reduce 函数的初始值
// 根据dir来确定从左侧或右侧来确定组合方向
function createReduce(dir) {// Optimized iterator function as using arguments.length// in the main function will deoptimize the, see #1991. function iterator(obj, iteratee, memo, keys, index, length) { for(; index >= 0 && index < length; index += dir) { var currentKey = keys ? keys[index] : index;//迭代函数的第一个值是memo(初始值),会被每一次成功调用iteratee函数的返回值所取代 。//第二个值是value,第三个是key或者index,第四个是obj(数组或类数组对象) memo = iteratee(memo, obj[currentKey], currentKey, obj); } return memo; } return function(obj, iteratee, memo, context) { iteratee = optimizeCb(iteratee, context, 4); var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, index = dir > 0 ? 0 : length - 1;// Determine the initial value if none is provided.//如果没有提供memo的初始值,即参数长度少于3//memo就设置为obj的第一个值(value或者index) if(arguments.length < 3) { memo = obj[keys ? keys[index] : index]; index += dir; } return iterator(obj, iteratee, memo, keys, index, length); }; }
// 归纳函数 目的:将一个值列表归纳为一个单一的结果 ,也叫做注入/折叠
// _.reduce(list, iteratee, [memo], [context]) Aliases: inject, foldl
// 别名为 inject 和 foldl, reduce方法把list中元素归结为一个单独的数值
// Reduce builds up a single result from a list of values, aka inject
,or foldl
.
.reduce = .foldl = _.inject = createReduce(1);
// var sum = _.reduce([1,2,3,4],function(memo,num){
// return memo+num;
// },0)
// console.log(sum)
//10
/ The right-associative version of reduce, also known as foldr
.
.reduceRight = .foldr = createReduce(-1);
/* 12月25号 */
// Return the first value which passes a truth test. Aliased as detect
.
//predicate 为迭代函数真值检测,返回一个布尔值,
// _.find()返回第一个匹配的元素,然后结束,如果没有找到则返回 undefined
// 如果找到匹配的元素,函数将立即返回,不会遍历整个list。
.find = .detect = function(obj, predicate, context) {
var key;
if(isArrayLike(obj)) {
key = _.findIndex(obj, predicate, context);
} else {
key = _.findKey(obj, predicate, context);
}
if(key !== void 0 && key !== -1) return obj[key];
};
// var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); => 2
// Return all the elements that pass a truth test.// Aliased as `select`.//predicate 为迭代函数真值检测,返回一个布尔值,//_.filter()返回所有满足predicate函数的元素组成的数组_.filter = _.select = function(obj, predicate, context) { var results = []; predicate = cb(predicate, context); //通过each来遍历所有元素 _.each(obj, function(value, index, list) { if(predicate(value, index, list)) results.push(value); }); return results;};
// var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); => [2, 4, 6]
// Return all the elements for which a truth test fails.// 返回所有不满足真值检测条件的元素组成的数组,与filter相反_.reject = function(obj, predicate, context) { return _.filter(obj, _.negate(cb(predicate)), context);};
// var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); => [1, 3, 5]
// Determine whether all of the elements match a truth test.// Aliased as `all`.//如果list中的所有元素都通过predicate的真值检测就返回true_.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;};
// .every([true, 1, null, ‘yes’], .identity); => false
// Determine if at least one element in the object matches a truth test.// Aliased as `any`.//some与find有点类似,不过find返回的是第一个匹配的元素,some返回的是布尔值//一旦找到了符合条件的元素, 就直接中断对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; };
// _.some([null, 0, 'yes', false]);// true// Determine if the array or object contains a given value (using `===`).// Aliased as `includes` and `include`.
_.contains = _.includes = _.include = function(obj, target, fromIndex) { // 如果不是数组,则将获取对象的value属性构成的数组 if(!isArrayLike(obj)) obj = _.values(obj); // 运用短路运算符优化性能 return _.indexOf(obj, target, typeof fromIndex == 'number' && fromIndex) >= 0; };
// _.contains([1, 2, 3], 3); => true
// Invoke a method (with arguments) on every item in a collection.
// 调用函数
_.invoke = function(obj, method) { // 利用Array.prototype.slice.call()将arguments转化为数组 var args = slice.call(arguments, 2); //判断method是否为函数 var isFunc = _.isFunction(method); // 使用map函数去遍历obj,将符合条件的重新绑定对象并返回一个新的数组,该数组存储了所有方法的处理结果 return _.map(obj, function(value) { // 此处method可能是一个回调函数,也可能是一个函数名,如果是函数名,通过value[method]来调用 //_.invoke([5, 1, 7]], 'sort'); [1, 5, 7] var func = isFunc ? method : value[method]; return func == null ? func : func.apply(value, args); }); };
// _.invoke([[5, 1, 7], [3, 2, 1]], ‘sort’); => [[1, 5, 7], [1, 2, 3]]
// Convenience version of a common use case of `map`: fetching a property.// pluck 为map函数的简化模型,可以只map里面的某一个key的value值
_.pluck = function(obj, key) { return _.map(obj, _.property(key)); };
// var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
// _.pluck(stooges, ‘name’);
// => [“moe”, “larry”, “curly”]
//遍历list中的每一个值,返回一个数组,这个数组包含properties所列出的属性的所有的 键 - 值对。//如果没有找到则返回 undefined// Convenience version of a common use case of `filter`: selecting only objects// containing specific `key:value` pairs.
_.where = function(obj, attrs) { return _.filter(obj, _.matcher(attrs)); };
//遍历整个list,返回匹配 properties参数所列出的所有 键 - 值 对的第一个值。//如果没有找到则返回 undefined// 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).
_.max = function(obj, iteratee, context) { var result = -Infinity, lastComputed = -Infinity, value, computed;// 判断是否为数组,若是,则直接比较,若为对象或类数组对象,则比较value值 if(iteratee == null && obj != null) { obj = isArrayLike(obj) ? obj : _.values(obj); for(var i = 0, length = obj.length; i < length; i++) { value = obj[i]; if(value > result) { result = value; } } } else { iteratee = cb(iteratee, context); _.each(obj, function(value, index, list) { computed = iteratee(value, index, list); if(computed > lastComputed || computed === -Infinity && result === -Infinity) { result = value; lastComputed = computed; } }); } return result; };