本文同步自我得博客:http://www.joeray61.com
前两天在微博上看到SF的微博引荐了我的前两篇文章,有点不测和欣喜。作为一个菜鸟,真的是倍受鼓舞,我写博客的动力也更足够了。
没看过前两篇博客的朋侪能够戳这里:Underscore源码剖析(一)、Underscore源码剖析(二)
上一篇文章引见了underscore的10个函数的详细完成细节,本日将继承引见其他的函数。
_.invoke
_.invoke = function(obj, method) {
// 挪用同名要领时通报的参数(从第3个参数最先)
var args = slice.call(arguments, 2);
// 顺次挪用每一个元素的要领, 并将效果放入数组中返回
return _.map(obj, function(value) {
return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
});
};
这个函数顺次挪用鸠合中一切元素的同名要领,从第3个参数最先的一切参数将被传入到元素的挪用要领中,末了返回一个数组,该数组存储了一切要领的处置惩罚效果
_.pluck
_.pluck = function(obj, key) {
// 假如某一个对象中不存在该属性, 则返回undefined
return _.map(obj, function(value) {
return value[key];
});
};
这个函数遍历了一个由对象列表构成的鸠合,并返回每一个对象中的指定属性的值列表
_.max
_.max = function(obj, iterator, context) {
// 假如鸠合是一个数组, 且没有运用处置惩罚器, 则运用Math.max猎取最大值
// 平常会是在一个数组存储了一系列Number范例的数据
if(!iterator && _.isArray(obj) && obj[0] === +obj[0])
return Math.max.apply(Math, obj);
// 关于空值, 直接返回负无穷大
if(!iterator && _.isEmpty(obj))
return -Infinity;
// 一个暂时的对象, computed用于在比较历程当中存储最大值(暂时的)
var result = {
computed : -Infinity
};
// 迭代鸠合中的元素
each(obj, function(value, index, list) {
// 假如指定了处置惩罚器参数, 则比较的数据为处置惩罚器返回的值, 不然直接运用each遍用时的默许值
var computed = iterator ? iterator.call(context, value, index, list) : value;
// 假如比较值比拟上一个值要大, 则将当前值放入result.value
computed >= result.computed && ( result = {
value : value,
computed : computed
});
});
// 返回最大值
return result.value;
};
望文生义,这个函数用来返回鸠合中的最大值, 假如不存在可比较的值, 则返回undefined
_.min
_.min = function(obj, iterator, context) {
if(!iterator && _.isArray(obj) && obj[0] === +obj[0])
return Math.min.apply(Math, obj);
if(!iterator && _.isEmpty(obj))
return Infinity;
var result = {
computed : Infinity
};
each(obj, function(value, index, list) {
var computed = iterator ? iterator.call(context, value, index, list) : value;
computed < result.computed && ( result = {
value : value,
computed : computed
});
});
return result.value;
};
这个函数没有加解释,由于完成历程与max基础雷同,用于返回鸠合中的最小值
_.shuffle
_.shuffle = function(obj) {
// shuffled变量存储处置惩罚历程及终究的效果数据
var shuffled = [], rand;
// 迭代鸠合中的元素
each(obj, function(value, index, list) {
// 天生一个随机数, 随机数在<0-当前已处置惩罚的数目>之间
rand = Math.floor(Math.random() * (index + 1));
// 将已随机获得的元素放到shuffled数组末端
shuffled[index] = shuffled[rand];
// 在前面获得的随机数的位置插进去最新值
shuffled[rand] = value;
});
// 返回一个数组, 该数组中存储了经由随机混排的鸠合元素
return shuffled;
};
这个函数是经由过程随机数, 让数组不必分列,实际上是完成了一个模仿洗牌历程的算法
_.sortBy
_.sortBy = function(obj, val, context) {
// val应当是对象的一个属性, 或一个处置惩罚器函数, 假如是一个处置惩罚器, 则应当返回须要举行比较的数据
var iterator = _.isFunction(val) ? val : function(obj) {
return obj[val];
};
// 挪用递次: _.pluck(_.map().sort());
// 挪用_.map()要领遍历鸠合, 并将鸠合中的元素放到value节点, 将元素中须要举行比较的数据放到criteria属性中
// 挪用sort()要领将鸠合中的元素依据criteria属性中的数据举行递次排序
// 挪用pluck猎取排序后的对象鸠兼并返回
return _.pluck(_.map(obj, function(value, index, list) {
return {
value : value,
criteria : iterator.call(context, value, index, list)
};
}).sort(function(left, right) {
var a = left.criteria, b = right.criteria;
if(a ===
void 0)
return 1;
if(b ===
void 0)
return -1;
return a < b ? -1 : a > b ? 1 : 0;
}), 'value');
};
这个函数对鸠合中元素, 依据特定的字段或值举行分列,比拟Array.prototype.sort要领, sortBy要领支撑对对象排序
_.groupBy
_.groupBy = function(obj, val) {
var result = {};
// val将被转换为举行分组的处置惩罚器函数, 假如val不是一个Function范例的数据, 则将被作为挑选元素时的key值
var iterator = _.isFunction(val) ? val : function(obj) {
return obj[val];
};
// 迭代鸠合中的元素
each(obj, function(value, index) {
// 将处置惩罚器的返回值作为key, 并将雷同的key元素放到一个新的数组
var key = iterator(value, index);
(result[key] || (result[key] = [])).push(value);
});
// 返回已分组的数据
return result;
};
这个函数将鸠合中的元素, 按处置惩罚器返回的key分为多个数组
_.sortedIndex
_.sortedIndex = function(array, obj, iterator) {
// 假如没有指定处置惩罚器参数, 则运用默许的处置惩罚器函数,该函数会返回参数自身
iterator || ( iterator = _.identity);
var low = 0, high = array.length;
// 不停与中心值对照,寻觅obj的准确插进去点
while(low < high) {
// (low + high) >> 1 相当于 Math.floor((low + high) / 2)
var mid = (low + high) >> 1;
iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
}
// 返回obj插进去array以后的索引号
return low;
};
这个函数的作用是将obj插进去已排序的array中,返回obj在array中的索引号
_.toArray
_.toArray = function(obj) {
if(!obj)
return [];
if(_.isArray(obj))
return slice.call(obj);
// 将arguments转换为数组
if(_.isArguments(obj))
return slice.call(obj);
if(obj.toArray && _.isFunction(obj.toArray))
return obj.toArray();
// 将对象转换为数组, 数组中包含对象中一切属性的值列表(不包含对象原型链中的属性)
return _.values(obj);
};
这个函数很简单,作用是将一个鸠合转换一个数组并返回
_.size
_.size = function(obj) {
// 假如鸠合是一个数组, 则盘算数组元素数目
// 假如鸠合是一个对象, 则盘算对象中的属性数目(不包含对象原型链中的属性)
return _.isArray(obj) ? obj.length : _.keys(obj).length;
};
这个函数用于盘算鸠合中元素的数目,isArray和keys函数后面会引见到
_.first / _.head / _.take
_.first = _.head = _.take = function(array, n, guard) {
// 假如没有指定参数n, 则返回第一个元素
// 假如指定了n, 则返回一个新的数组, 包含递次指定数目n个元素
// guard参数用于肯定只返回第一个元素, 当guard为true时, 指定数目n无效
return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
};
这个函数用于返回一个数组的第一个或顺序指定的n个元素
_.initial
_.initial = function(array, n, guard) {
// 假如没有通报参数n, 则默许返回除末了一个元素外的别的元素
// 假如通报参数n, 则返回从末了一个元素最先向前的n个元素外的别的元素
// guard用于肯定只返回一个元素, 当guard为true时, 指定数目n无效
return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
};
这个函数返回一个新数组, 包含除末了一个元素外的别的元素, 或消除从末了一个元素最先向前指定n个元素
_.last
_.last = function(array, n, guard) {
if((n != null) && !guard) {
// 盘算并指定猎取的元素位置n, 直到数组末端, 作为一个新的数组返回
return slice.call(array, Math.max(array.length - n, 0));
} else {
// 假如没有指定数目, 或guard为true时, 只返回末了一个元素
return array[array.length - 1];
}
};
这个函数与first相反,返回数组的末了一个或倒序指定的n个元素
_.rest / _.tail
_.rest = _.tail = function(array, index, guard) {
// 盘算slice的第二个位置参数, 直到数组末端
// 假如没有指定index, 或guard值为true, 则返回除第一个元素外的别的元素
// (index == null)值为true时, 作为参数通报给slice函数将被自动转换为1
return slice.call(array, (index == null) || guard ? 1 : index);
};
这个函数与initial相反,用于猎取除了第一个或指定前n个元素外的别的元素
_.campact
_.compact = function(array) {
return _.filter(array, function(value) {
return !!value;
});
};
这个函数借助filter函数,返回数组中一切值能被转换为true的元素, 返回一个新的数组,不能被转换的值包含 false, 0, ”, null, undefined, NaN, 这些值将被转换为false
_.flatten
_.flatten = function(array, shallow) {
// 迭代数组中的每一个元素, 并将返回值作为demo通报给下一次迭代
return _.reduce(array, function(memo, value) {
// 假如元素依然是一个数组, 举行以下推断:
// - 假如不举行深层兼并, 则运用Array.prototype.concat将当前数组和之前的数据举行衔接
// - 假如支撑深层兼并, 则迭代挪用flatten要领, 直到底层元素不再是数组范例
if(_.isArray(value))
return memo.concat( shallow ? value : _.flatten(value));
// 数据(value)已处于底层, 不再是数组范例, 则将数据兼并到memo中并返回
memo[memo.length] = value;
return memo;
}, []);
};
这个函数用于将一个多维数组合成为一维数组, 支撑深层兼并,个中第二个参数shallow用于掌握兼并深度, 当shallow为true时, 只兼并第一层, 默许举行深层兼并
_.without
_.without = function(array) {
return _.difference(array, slice.call(arguments, 1));
};
这个函数用于挑选并返回当前数组中与指定数据不相等的差别数据,详细能够参看我后续对difference函数的引见
_.uniq/_.unique
_.uniq = _.unique = function(array, isSorted, iterator) {
// 假如运用了iterator处置惩罚器, 则先将当前数组中的数据会先经由按迭代器处置惩罚, 并返回一个处置惩罚后的新数组
// 新数组用于作为比较的基准
var initial = iterator ? _.map(array, iterator) : array;
// 用于纪录处置惩罚效果的暂时数组
var results = [];
// 假如数组中只要2个值, 则不须要运用include要领举行比较, 将isSorted设置为true能进步运转效力
if(array.length < 3)
isSorted = true;
// 运用reduce要领迭代并累加处置惩罚效果
// initial变量是须要举行比较的基准数据, 它多是原始数组, 也多是处置惩罚器的效果鸠合(假如设置过iterator)
_.reduce(initial, function(memo, value, index) {
// 假如isSorted参数为true, 则直接运用===比较纪录中的末了一个数据
// 假如isSorted参数为false, 则运用include要领与鸠合中的每一个数据举行对照
if( isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) {
// memo纪录了已比较过的无反复数据
// 依据iterator参数的状况, memo中纪录的数据多是原始数据, 也多是处置惩罚器处置惩罚后的数据
memo.push(value);
// 处置惩罚效果数组中保留的一直为原始数组中的数据
results.push(array[index]);
}
return memo;
}, []);
// 返回处置惩罚效果, 它只包含数组中无反复的数据
return results;
};
这个函数用于对数组中的数据举行去重(运用===举行比较),当isSorted参数不为false时, 将顺次对数组中的元素挪用include要领, 搜检雷同元素是不是已被添加到返回值(数组)中,假如挪用之前确保数组中数据按递次分列, 则能够将isSorted设为true, 它将经由过程与末了一个元素举行对照来消除雷同值, 运用isSorted效力会高于默许的include体式格局,uniq要领默许将以数组中的数据举行对照, 假如声明iterator处置惩罚器, 则会依据处置惩罚器建立一个对照数组, 比较时以该数组中的数据为准, 但终究返回的唯一数据仍然是原始数组
_.union
_.union = function() {
// union对参数中的多个数组举行浅层兼并为一个数组对象通报给uniq要领举行处置惩罚
return _.uniq(_.flatten(arguments, true));
};
这个函数与uniq作用一致, 不同之处在于union许可在参数中传入多个数组
_.intersection
_.intersection = _.intersect = function(array) {
// rest变量纪录须要举行比较的别的数组对象
var rest = slice.call(arguments, 1);
// 运用uniq要领去除当前数组中的反复数据, 防止反复盘算
// 对当前数组的数据经由过程处置惩罚器举行过滤, 并返回相符前提(比较雷同元素)的数据
return _.filter(_.uniq(array), function(item) {
// 运用every要领考证每一个数组中都包含了须要对照的数据
// 假如一切数组中均包含对照数据, 则悉数返回true, 假如恣意一个数组没有包含该元素, 则返回false
return _.every(rest, function(other) {
// other参数存储了每一个须要举行对照的数组
// item存储了当前数组中须要举行对照的数据
// 运用indexOf要领搜刮数组中是不是存在该元素(可参考indexOf要领解释)
return _.indexOf(other, item) >= 0;
});
});
};
这个函数用于猎取当前数组与别的一个或多个数组的交集元素,从第二个参数最先为须要举行比较的一个或多个数组
_.difference
_.difference = function(array) {
// 对第2个参数最先的一切参数, 作为一个数组举行兼并(仅兼并第一层, 而并不是深层兼并)
// rest变量存储考证数据, 在本要领中用于与原数据对照
var rest = _.flatten(slice.call(arguments, 1), true);
// 对兼并后的数组数据举行过滤, 过滤前提是当前数组中不包含参数指定的考证数据的内容
// 将相符过滤前提的数据组合为一个新的数组并返回
return _.filter(array, function(value) {
return !_.include(rest, value);
});
};
这个函数会挑选并返回当前数组中与指定数据不相等的差别数据,平常用于删除数组中指定的数据, 并获得删除后的新数组
小结
本日一共引见了21个函数的详细完成,我都写累了,人人能够也看累了吧,我以为写太多也不利于人人消化这些学问,本日就到这儿吧。thx for reading, hope u enjoy