each _.each(list, iteratee, [context])
Alias: forEach
遍历list中的一切元素,按递次用遍历输出每一个元素。假如通报了context参数,则把iteratee绑定到context对象上。每次挪用iteratee都邑通报三个参数:(element, index, list)。假如list是个JavaScript对象,iteratee的参数是 (value, key, list))。返回list以轻易链式挪用。
_.each([1, 2, 3], alert);
=> alerts each number in turn...
_.each({one: 1, two: 2, three: 3}, alert);
=> alerts each number value in turn...
_.each
源码
// 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.
_.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);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
剖析
_.each([1, 2, 3], alert); // _.each()运用要领,个中`alert`能够换成本身写的function
obj
是[1, 2, 3]
, iteratee
是alert
, context
没有
iteratee = optimizeCb(iteratee, context);
起首是挪用optimizeCb()
函数
剖析 optimizeCb
源码
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func;
};
由于context
没有,所以这里直接返回alert
, 所以 iteratee
现在是alert
再运用 isArrayLike
推断 传进来的obj
是不是是数组,推断数组的要领
//道理就是经由过程推断它是不是具有长度且长度大于0且小于MAX_ARRAY_INDEX
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
var length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};
由于这里是数组,所以继承
// 经由过程 for 轮回来遍历数组内里每一个值,传给 iteratee 函数来运转
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj); // 即是 alert(obj[i], i, obj);
}
假如不是数组呢?对象默许是没有length
属性的
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
运用了_.keys()
函数,下面剖析 _keys()
源码
_.keys = function(obj) {
if (!_.isObject(obj)) return [];
if (nativeKeys) return nativeKeys(obj);
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key);
// Ahem, IE < 9.
if (hasEnumBug) collectNonEnumProps(obj, keys);
return keys;
};
起首运用_.isObject
函数推断是不是是对象
// Is a given variable an object?
_.isObject = function(obj) {
var type = typeof obj;
return type === 'function' || type === 'object' && !!obj;
};
起首推断传进来的参数的范例,然后返回true
或许false
注重,经由过程以下两个例子可知, &&
的优先级比 ||
的高
console.log(true || false && false) // true
console.log(true || false && true) // true
然后假如浏览器支撑 ES5
的 Object.keys
要领,就优先运用
nativeKeys = Object.keys,
不支撑就继承遍历轮回 对象
var keys = [];
// own enumerable properties
for (var key in obj)
// hasOwnProperty
if (_.has(obj, key)) keys.push(key);
运用了 _.has()
函数,下面剖析_.has()
函数
// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
return obj != null && hasOwnProperty.call(obj, key);
};
经由过程推断 传进来的obj
是不是为null
而且挪用hasOwnProperty
要领推断该对象是不是有该键值
hasOwnProperty = ObjProto.hasOwnProperty = Object.prototype.hasOwnProperty;
假如有该属性,返回true
,这时候回到_.keys()
,该几乎push
到keys[]
内
// IE9以下不能用 for in 来遍历,所以运用collectNonEnumProps()函数来解决问题,临时能够不看
if (hasEnumBug) collectNonEnumProps(obj, keys);
这时候已把对象转化成数组了,回到_.each()
函数,继承运用for
轮回遍历数组 ,把参数通报给alert
函数
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj); // 即是 alert(obj[keys[i]], keys[i], obj);
}
末了再返回obj
全部剖析_.each()
函数,接踵剖析了_.has()
和_.keys()
函数,也许看了一下underscore.js
的源码,觉得不是太难,一个函数一个函数剖析就好。