一、_.each(list, iterator, [context]):對集合中每一元素執行處理器方法.javascript
若是傳遞了context參數,則把iterator綁定到context對象上。每次調用iterator都會傳遞三個參數:(element, index, list)。若是list是個JavaScript對象,iterator的參數是 (value, key, list))。若是存在原生的forEach方法,Underscore就使用它代替。java
var each = _.each = _.forEach = function(obj, iterator, context) { //不處理null if (obj == null) return; //宿主環境支持foreach,則優先調用 if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); //obj.length是number,之後for循環都須要加這個條件 } else if (obj.length === +obj.length) { //obj爲數組 for (var i = 0, l = obj.length; i < l; i++) { //i是obj的序號,iterator的返回值若是是breaker的話,則終止;breaker是內部對象,只在any中進行調用 if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; } } else { //obj爲對象 for (var key in obj) { //不考慮原型鏈的屬性 if (_.has(obj, key)) { if (iterator.call(context, obj[key], key, obj) === breaker) return; } } } };
二、_.map(list, iterator, [context])
:經過變換函數(iterator迭代器)把list中的每一個值映射到一個新的數組中數組
_.map = _.collect = function(obj, iterator, context) { var results = []; if (obj == null) return results; if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); each(obj, function(value, index, list) { //自增數組;iterator須要有返回值; results[results.length] = iterator.call(context, value, index, list); }); //若是是數組的話,必定要返回相同長度的新數組 if (obj.length === +obj.length) results.length = obj.length; return results; }; var a = [1,2,3,4,5]; var result = _.map(a, function(value){ if(value < 3){ return value%2 ? value:0; } }) console.log(result);
三、_.reduce():list中元素歸結爲一個單獨的數值 app
Memo是reduce函數的初始值,reduce的每一步都須要由iterator返回。這個迭代傳遞4個參數:memo, value 和 迭代的index(或者 key)和最後一個引用的整個 list。dom
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { var initial = arguments.length > 2; if (obj == null) obj = []; if (nativeReduce && obj.reduce === nativeReduce) { //爲何用bind,而不用call方法呢? if (context) iterator = _.bind(iterator, context); return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); } each(obj, function(value, index, list) { if (!initial) { //若是沒有memo,則把第一個值做爲memo;只是考慮第一次的狀況,真巧妙 memo = value; initial = true; } else { memo = iterator.call(context, memo, value, index, list); } });
//TypeError:內置的js對象 if (!initial) throw new TypeError('Reduce of empty array with no initial value'); return memo; };
四、_reduceRight():從右側開始執行reduce函數curl
_.reduceRight = _.foldr = function(obj, iterator, memo, context) { var initial = arguments.length > 2; if (obj == null) obj = []; if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { if (context) iterator = _.bind(iterator, context); return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); } //函數反轉 var reversed = _.toArray(obj).reverse(); if (context && !initial) iterator = _.bind(iterator, context); return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); };
五、_.find():遍歷list,返回第一個經過iterator迭代器真值檢測的元素值.ide
若是沒有值傳遞給測試迭代器將返回undefined。 若是找到匹配的元素,函數將當即返回,不會遍歷整個list。 函數
_.find = _.detect = function(obj, iterator, context) { var result;
//找到一個就返回 any(obj, function(value, index, list) { if (iterator.call(context, value, index, list)) { result = value;
//any iterator return true return true; } }); return result; };
六、_.filter():遍歷list中的每一個值,返回包含全部經過iterator真值檢測的元素值。若是存在原生filter方法,則用原生的filter方法。測試
_.filter = _.select = function(obj, iterator, context) { var results = []; if (obj == null) return results; if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); each(obj, function(value, index, list) { //自增函數 if (iterator.call(context, value, index, list)) results[results.length] = value; }); return results; };
七、_.reject():返回沒有用過iterator真值檢測的元素值,與filter相反url
_.reject = function(obj, iterator, context) { var results = []; if (obj == null) return results; each(obj, function(value, index, list) { if (!iterator.call(context, value, index, list)) results[results.length] = value; }); return results; };
八、_.every():若是list中的全部元素都經過iterator的真值檢測就返回true。
_.every = _.all = function(obj, iterator, context) { var result = true; if (obj == null) return result; if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); each(obj, function(value, index, list) { //result = (result && iterator.call(context, value, index, list)) 過高明瞭 if (!(result = result && iterator.call(context, value, index, list))) return breaker; }); return !!result; };
九、_.any(): 若是list中有任何一個元素經過 iterator 的真值檢測就返回true。也叫some
一旦找到了符合條件的元素, 就直接中斷對list的遍歷. 若是存在原生的some方法,就使用原生的some
var any = _.some = _.any = function(obj, iterator, context) {
//若是iterator存在,則繼續;若是iterator不存在,則執行iterator = _.identity(默認的迭代器或處理器) iterator || (iterator = _.identity); var result = false; if (obj == null) return result; if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); each(obj, function(value, index, list) { if (result || (result = iterator.call(context, value, index, list))) return breaker; });
//!!通常用來將後面的表達式強制轉換爲布爾類型的數據(boolean),也就是隻能是true或者false return !!result; };
十、_.include():集合中是否有值與目標參數徹底匹配(同時將匹配數據類型)
_.include = _.contains = function(obj, target) { var found = false; if (obj == null) return found; //這種return太好了 if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; found = any(obj, function(value) { return value === target; }); return found; };
十一、_.invoke():在list的每一個元素上執行methodName方法。 任何傳遞給invoke的額外參數,invoke都會在調用methodName方法的時候傳遞給它。
_.invoke = function(obj, method) { var args = slice.call(arguments, 2); return _.map(obj, function(value) { //不須要method||value //method能夠是對象的屬性名 return (_.isFunction(method) ? method || value : value[method]).apply(value, args); }); };
十二、_.pluck():獲取對象數組的屬性值
_.pluck = function(obj, key) { return _.map(obj, function(value){ return value[key]; }); }; 實例 var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; _.pluck(stooges, 'name'); => ["moe", "larry", "curly"]
1三、_.max():取最大值
1四、_.min():取最小值
_.min = function(obj, iterator, context) { //iterator不存在,obj是數組,且有值 if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj); //iterator不存在,obj爲空,返回最大值 if (!iterator && _.isEmpty(obj)) return Infinity; var result = {computed : Infinity}; each(obj, function(value, index, list) { //iterator存在,執行iterator;不存在,computed爲當前值; var computed = iterator ? iterator.call(context, value, index, list) : value; //當前計算值小於以前計算值,給result賦值;不小於的話,不賦值;把&&當if用 computed < result.computed && (result = {value : value, computed : computed}); }); return result.value; };
1五、_.shuffle():隨機亂序
_.shuffle = function(obj) { var shuffled = [], rand; each(obj, function(value, index, list) { //隨機數在0到當前已處理的數量之間 rand = Math.floor(Math.random() * (index + 1)); //交換隨機數與當前序號的值 shuffled[index] = shuffled[rand]; shuffled[rand] = value; }); return shuffled; };
1六、_.sortBy():返回一個排序後的list拷貝副本。
若是有iterator參數,iterator將做爲list排序的依據。迭代器也能夠是字符串的屬性的名稱進行排序的(好比 length)。相比Array.prototype.sort,sortBy()支持對對象排序
_.sortBy = function(obj, val, context) { //val是處理器,返回須要比較的值;val是對象的屬性,返回屬性的值 var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; // 調用順序: _.pluck(_.map().sort()); // 調用_.map()方法遍歷集合, 並將集合中的元素放到value節點, 將元素中須要進行比較的數據放到criteria屬性中 // 調用sort()方法將集合中的元素按照criteria屬性中的數據進行順序排序 // 調用pluck獲取排序後的對象集合並返回 return _.pluck(_.map(obj, function(value, index, list) { return { value : value, criteria : iterator.call(context, value, index, list) }; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; if (a === void 0) return 1; if (b === void 0) return -1; //不明白爲何這麼寫? return a < b ? -1 : a > b ? 1 : 0; }), 'value'); };
1七、_.groupBy(list, iterator, [context])把一個集合分組爲多個集合,經過 iterator 返回的結果進行分組.
若是 iterator 是一個字符串而不是函數, 那麼將使用 iterator 做爲各元素的屬性名來對比進行分組.
_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); }); => {1: [1.3], 2: [2.1, 2.4]} _.groupBy(['one', 'two', 'three'], 'length'); => {3: ["one", "two"], 5: ["three"]} _.groupBy = function(obj, val) { var result = {}; var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; each(obj, function(value, index) { var key = iterator(value, index); //|| 和 &&用得真好;若是result[key]不存在的話,賦爲[];若是result[key]存在的話,給他push (result[key] || (result[key] = [])).push(value); }); return result; };
1八、_.sortedIndex(list, value, [iterator], [context]): 使用二分查找肯定value在list中的位置序號,value按此序號插入能保持list原有的排序。
若是提供iterator函數,iterator將做爲list排序的依據,包括你傳遞的value 。 iterator也能夠是字符串的屬性名用來排序(好比length)。
_.sortedIndex([10, 20, 30, 40, 50], 35); => 3 var stooges = [{name: 'moe', age: 40}, {name: 'curly', age: 60}]; _.sortedIndex(stooges, {name: 'larry', age: 50}, 'age'); => 1 _.sortedIndex = function(array, obj, iterator) { iterator || (iterator = _.identity); var low = 0, high = array.length; while (low < high) { //(low+high) >> 1右移一位,不是/2,由於右移的話,小數就沒了 var mid = (low + high) >> 1; iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; } return low; };
1九、_.toArray():轉爲數組
_.toArray = function(obj) { if (!obj) return []; if (_.isArray(obj)) return slice.call(obj); if (_.isArguments(obj)) return slice.call(obj); if (obj.toArray && _.isFunction(obj.toArray)) return obj.toArray(); // 將對象轉換爲數組, 數組中包含對象中全部屬性的值列表(不包含對象原型鏈中的屬性) return _.values(obj); };
20、_.size():
_.size = function(obj) { //若是是對象,則返回屬性的個數(不包含原型鏈) return _.isArray(obj) ? obj.length : _.keys(obj).length; };