接着第一课,我们看下collection函数集中剩下的几个

  // Invoke a method (with arguments) on every item in a collection.
  _.invoke = function(obj, method) {
    var args = slice.call(arguments, 2);
    return _.map(obj, function(value) {
      return (method.call ? method || value : value[method]).apply(value, args);
    });
  };

  // Convenience version of a common use case of `map`: fetching a property.
  _.pluck = function(obj, key) {
    return _.map(obj, function(value){ return value[key]; });
  };

  // Return the maximum element or (element-based computation).
  _.max = function(obj, iterator, context) {
    if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
    if (!iterator && _.isEmpty(obj)) return -Infinity;
    var result = {computed : -Infinity};
    each(obj, function(value, index, list) {
      var computed = iterator ? iterator.call(context, value, index, list) : value;
      computed >= result.computed && (result = {value : value, computed : computed});
    });
    return result.value;
  };

  // Return the minimum element (or element-based computation).
  _.min = function(obj, iterator, context) {
    if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
    if (!iterator && _.isEmpty(obj)) return Infinity;
    var result = {computed : Infinity};
    each(obj, function(value, index, list) {
      var computed = iterator ? iterator.call(context, value, index, list) : value;
      computed < result.computed && (result = {value : value, computed : computed});
    });
    return result.value;
  };

  // Shuffle an array.
  _.shuffle = function(obj) {
    var shuffled = [], rand;
    each(obj, function(value, index, list) {
      if (index == 0) {
        shuffled[0] = value;
      } else {
        rand = Math.floor(Math.random() * (index + 1));
        shuffled[index] = shuffled[rand];
        shuffled[rand] = value;
      }
    });
    return shuffled;
  };

  // Sort the object's values by a criterion produced by an iterator.
  _.sortBy = function(obj, iterator, context) {
    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;
      return a < b ? -1 : a > b ? 1 : 0;
    }), 'value');
  };

  // Groups the object's values by a criterion produced by an iterator
  _.groupBy = function(obj, iterator) {
    var result = {};
    each(obj, function(value, index) {
      var key = iterator(value, index);
      (result[key] || (result[key] = [])).push(value);
    });
    return result;
  };

  // Use a comparator function to figure out at what index an object should
  // be inserted so as to maintain order. Uses binary search.
  _.sortedIndex = function(array, obj, iterator) {
    iterator || (iterator = _.identity);
    var low = 0, high = array.length;
    while (low < high) {
      var mid = (low + high) >> 1;
      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
    }
    return low;
  };

  // Safely convert anything iterable into a real, live array.
  _.toArray = function(iterable) {
    if (!iterable) return [];
    if (iterable.toArray) return iterable.toArray();
    if (_.isArray(iterable)) return slice.call(iterable);
    if (_.isArguments(iterable)) return slice.call(iterable);
    return _.values(iterable);
  };

  // Return the number of elements in an object.
  _.size = function(obj) {
    return _.toArray(obj).length;
  };

  invoke(list,methodName,[*arguments]):和map差不多,都是对list中的每一项执行methodName这个方法,不一样的是invoke支持传递额外的参数,而且第二个参数可以是一个具体的函数,也可以是一个函数名,该函数可以通过listItem[methodName]访问到,例如:

1 _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
2 => [[1, 5, 7], [1, 2, 3]]

  pluck(obj,key):key为obj中每一项的某一个属性名,函数执行后返回一个数组,每一项都是obj中每一项对应key的value。

  max(obj,iterator,context):遍历obj的每一项并传入iterator中计算,每次计算都会和上一次计算后的结果比较,并记录计算后的最大值和对应的项,最后返回最大值对应的项,如果只传入一个数组作为参数,则返回该数组的最大值。

  min:和max类似。

  shuffle(obj):洗牌,这个函数其实挺有意思的,它其实就是对给定的一个数组进行洗牌,返回一个新数组,新数组中的每一项都在原数组中,但是顺序是随机的,内部实现是先声明一个洗牌后的数组shuffled,然后遍历原数组的每一项item,生成一个0-shuffled的length-1的随机数random,然后把shuffled的random索引处的值赋给shuffled[length],最后把item放到shuffled[random],这个洗牌算法大家可以参考下这里http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

  sortBy(obj,iterator,context):对obj按照iterator映射后的结果进行排序,内部实现是先对obj进行map操作,每一项都映射为一个对象,这个对象的value属性为obj中每一项的原始值,criteria属性为iterator.call(context,value,index,list)后的返回值,然后对这个数组进行排序,排序的依据是criteria属性值的大小,最后用pluck采摘排序后每一项的value属性值(原始值)

  groupBy(obj,iterator):类似sql中的groupBy,就是对计算结果进行分组,内部是声明一个result对象,obj的每一项都传入iterator中计算,计算后的值作为result的一个key,如果多个item计算后的key相同,那么就push进result[key],最后返回result

  sortedIndex(array,obj,iterator):计算一个obj在一个排好序的数组中的位置,array就是一个排好序的数组,内部实现是使用二分查找法,如果没有传入自定义的比较函数就用_.identity(其实就是比较obj本身)

  toArray(iterator):把任何可迭代的对象都转换为数组,支持数组,类数组集合,有原生toArray方法的对象,以及普通对象(返回keys)

  size(obj):返回obj toArray后的大小。

  这就是Underscore提供给我们的20个collection操作函数,下面我们看下操作array的工具函数:

 // Array Functions
  // ---------------

  // Get the first element of an array. Passing **n** will return the first N
  // values in the array. Aliased as `head`. The **guard** check allows it to work
  // with `_.map`.
  _.first = _.head = function(array, n, guard) {
    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
  };

  // Returns everything but the last entry of the array. Especcialy useful on
  // the arguments object. Passing **n** will return all the values in
  // the array, excluding the last N. The **guard** check allows it to work with
  // `_.map`.
  _.initial = function(array, n, guard) {
    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
  };

  // Get the last element of an array. Passing **n** will return the last N
  // values in the array. The **guard** check allows it to work with `_.map`.
  _.last = function(array, n, guard) {
    return (n != null) && !guard ? slice.call(array, array.length - n) : array[array.length - 1];
  };

  // Returns everything but the first entry of the array. Aliased as `tail`.
  // Especially useful on the arguments object. Passing an **index** will return
  // the rest of the values in the array from that index onward. The **guard**
  // check allows it to work with `_.map`.
  _.rest = _.tail = function(array, index, guard) {
    return slice.call(array, (index == null) || guard ? 1 : index);
  };

  // Trim out all falsy values from an array.
  _.compact = function(array) {
    return _.filter(array, function(value){ return !!value; });
  };

  // Return a completely flattened version of an array.
  _.flatten = function(array, shallow) {
    return _.reduce(array, function(memo, value) {
      if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
      memo[memo.length] = value;
      return memo;
    }, []);
  };

  // Return a version of the array that does not contain the specified value(s).
  _.without = function(array) {
    return _.difference(array, slice.call(arguments, 1));
  };

  // Produce a duplicate-free version of the array. If the array has already
  // been sorted, you have the option of using a faster algorithm.
  // Aliased as `unique`.
  _.uniq = _.unique = function(array, isSorted, iterator) {
    var initial = iterator ? _.map(array, iterator) : array;
    var result = [];
    _.reduce(initial, function(memo, el, i) {
      if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {
        memo[memo.length] = el;
        result[result.length] = array[i];
      }
      return memo;
    }, []);
    return result;
  };

  // Produce an array that contains the union: each distinct element from all of
  // the passed-in arrays.
  _.union = function() {
    return _.uniq(_.flatten(arguments, true));
  };

  // Produce an array that contains every item shared between all the
  // passed-in arrays. (Aliased as "intersect" for back-compat.)
  _.intersection = _.intersect = function(array) {
    var rest = slice.call(arguments, 1);
    return _.filter(_.uniq(array), function(item) {
      return _.every(rest, function(other) {
        return _.indexOf(other, item) >= 0;
      });
    });
  };

  // Take the difference between one array and another.
  // Only the elements present in just the first array will remain.
  _.difference = function(array, other) {
    return _.filter(array, function(value){ return !_.include(other, value); });
  };

  // Zip together multiple lists into a single array -- elements that share
  // an index go together.
  _.zip = function() {
    var args = slice.call(arguments);
    var length = _.max(_.pluck(args, 'length'));
    var results = new Array(length);
    for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
    return results;
  };

  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
  // we need this function. Return the position of the first occurrence of an
  // item in an array, or -1 if the item is not included in the array.
  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
  // If the array is large and already in sort order, pass `true`
  // for **isSorted** to use binary search.
  _.indexOf = function(array, item, isSorted) {
    if (array == null) return -1;
    var i, l;
    if (isSorted) {
      i = _.sortedIndex(array, item);
      return array[i] === item ? i : -1;
    }
    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
    for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
    return -1;
  };

  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
  _.lastIndexOf = function(array, item) {
    if (array == null) return -1;
    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
    var i = array.length;
    while (i--) if (array[i] === item) return i;
    return -1;
  };

  // Generate an integer Array containing an arithmetic progression. A port of
  // the native Python `range()` function. See
  // [the Python documentation](http://docs.python.org/library/functions.html#range).
  _.range = function(start, stop, step) {
    if (arguments.length <= 1) {
      stop = start || 0;
      start = 0;
    }
    step = arguments[2] || 1;

    var len = Math.max(Math.ceil((stop - start) / step), 0);
    var idx = 0;
    var range = new Array(len);

    while(idx < len) {
      range[idx++] = start;
      start += step;
    }

    return range;
  };

  first|head(array,n,guard):如果只传array则返回array[0],如果传n了就返回前n个元素,第三个参数guard文档上说是为了允许它和map一起工作,但是我还是不太理解。

  initial(array,n,guard):返回数组中不包括后n个元素的所有元素,如果没传n则n=1

  last(array,n,guard):返回数组的后n(没传nl时取1)个元素

  rest|tail(array,index,guard):返回数组中除了第一个元素外的其余的元素,如果传入index则返回array[index]及以后的元素

  compact(array):返回一个新数组,新数组是过滤掉数组中所有的falsy value,在js中即为undefined,null,0,false,NaN,"",内部是使用!!value来转换为布尔值。

  flatten(array,shallow):返回一个新数组,如果shallow为true,则把array中的array都拆分为单个的值(递归调用flatten)。

  difference(array,other):返回一个新数组,该数组是array和other的差集

  without(array,...):返回一个新数组,该数组是array和arguments.slice(1)的差集

  uniq|unique(array,isSorted,iterator):返回一个新数组,该数组是原数组去掉重复元素的版本,如果array是已经排好序的,那么内部会调用_,lash(array)来检测是否重复,这样会很快,如果不是排好序的内部会调用_.include(array,el)这样又是一层循环,相对前者要慢些。

  union():unique的包装函数,它把arguments用flatten(array,true)转换为数组,再对其调用unique返回新的无重复的数组。

  intersection|intersect(array):函数的参数是传入2个或更多的数组,运行结果是返回这几个数组的交集

  zip(*arrays):参数是多个数组,运行结果是返回一个数组,数组的长度为多个数组中length最大的那个,数组的第i项为各个数组相应的第i个元素组成的新数组

  indexOf(array,item,isSorted):返回item在array中的索引,如果是排好序的array则内部是调用_.sortedIndex进行二分查找,如果没有排序则调用es5的indexOf,如果不支持则逐个遍历吧,找不到的话就返回-1咯。

  lashIndexOf(array,item):和indexOf差不多,你懂的,只是不支持排好序的情况

  range([start],stop,[step]):和python的range实现类似的,如果只传一个参数则为stop

  

  

posted on 2011-10-20 15:01  冰王子(等待只为与你相遇)  阅读(669)  评论(0编辑  收藏  举报