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。具体解释
时间: 2024-10-22 10:38:49