isArrayLike 檢測是數組對象仍是純數組javascript
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 -> propertyhtml
property是個閉包java
簡化後:數組
getLength 返回的是一個函數閉包
var getLength = function(obj){ return obj['length']; }
當調用app
// collection = [1,2,3]函數
var length = getLength(collection);spa
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.htmlcode
<!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.jshtm
_.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。具體解釋