isArrayLike 检测是数组对象还是纯数组
var property = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
}; var getLength = property('length'); var isArrayLike = function(collection) {
var length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};
从下往上看 isArrayLike -> getLength -> property
property是个闭包
简化后:
getLength 返回的是一个函数
var getLength = function(obj){
return obj['length'];
}
当调用
// collection = [1,2,3]
var length = getLength(collection);
var isArrayLike = function(collection) {
// var length = [1,2,3]['length'];
var length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};
T5.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Underscore</title>
<script src="underscore.js"></script>
</head>
<body>
</body>
</html> <script type="text/javascript" src="T5.js"></script>
T5.js
_.each([1, 2, 3], alert);
执行过程:
1. 接着就进入了optimizeCb函数。
// obj = [1,2,3], iteratee = alert(), context = undefined
_.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;
};
2. optimizeCb 函数
// Internal function that returns an efficient (for current engines) version
// of the passed-in callback, to be repeatedly applied in other Underscore
// functions.
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func;
switch (argCount == null ? 3 : 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 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);
};
};
因为argCount = underfined。switch中的条件都不满足。
等于就直接执行了
return function() {
return func.apply(context, arguments);
};
3. isArrayLike 上面已分析过
var isArrayLike = function(collection) {
var length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};
返回true
4.
// 接着执行each中的
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
}
}
Tips:
1. context === void 0 判断context是否为undefined。具体解释