underscore collections

一、_.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;
  };
相關文章
相關標籤/搜索