map方法源码
_.map = _.collect = function(obj, iteratee, context) {
//对回调函数绑定上下文
iteratee = cb(iteratee, context);
//将obj与array两种情况巧妙的结合在一起,用&&操作符简化写法
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
results = Array(length);
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
cb方法
var builtinIteratee;
//argCount参数用于optimizeCb方法内部的判断
var cb = function(value, context, argCount) {
//不清楚为什么要判断
if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
//对迭代器的绑定做了三种情况的判断
//_.identity返回原值
if (value == null) return _.identity;
//是function则绑定上下文
if (_.isFunction(value)) return optimizeCb(value, context, argCount);
//是object则会返回一个isMatch方法,可以判断两个对象的自身属性是否匹配
if (_.isObject(value) && !_.isArray(value)) return _.matcher(value);
//不是以上三者,则
return _.property(value);
};
//iteratee方法只是cb的开放出的入口
_.iteratee = builtinIteratee = function(value, context) {
return cb(value, context, Infinity);
};
optimizeCb方法
//主要是为了避免使用arguments,优化性能。使用call而不是apply也是出于性能优化的考虑
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func;
switch (argCount) {
case 1: return function(value) {
return func.call(context, value);
};
// The 2-parameter case has been omitted only because no current consumers
// made use of it.
case null:
case 3: return function(value, index, collection) {
return func.call(context, value, index, collection);
};
case 4: return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
return function() {
return func.apply(context, arguments);
};
};
matcher方法
_.matcher = _.matches = function(attrs) {
//extendOwn用于copy对象自身的属性
attrs = _.extendOwn({}, attrs);
return function(obj) {
return _.isMatch(obj, attrs);
};
};
isMatch方法
//比对两个对象的属性是否完全匹配
_.isMatch = function(object, attrs) {
var keys = _.keys(attrs), length = keys.length;
if (object == null) return !length;
//确保得到一个对象
var obj = Object(object);
for (var i = 0; i < length; i++) {
var key = keys[i];
if (attrs[key] !== obj[key] || !(key in obj)) return false;
}
return true;
};
property方法
_.property = function(path) {
if (!_.isArray(path)) {
return shallowProperty(path);
}
return function(obj) {
return deepGet(obj, path);
};
};
deepGet
var deepGet = function(obj, path) {
var length = path.length;
for (var i = 0; i < length; i++) {
if (obj == null) return void 0;
obj = obj[path[i]];
}
//在循环中判断在前,递增在后,所以最后return时需要判断
return length ? obj : void 0;
};
shallowProperty
var shallowProperty = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};