目录

Underscore 数组

数组(Arrays)

1. _.first

_.first(array, [n]) Alias: head, take 返回array(数组)的第一个元素。传递 n参数将返回数组中从第一个元素开始的n个元素(愚人码头注:返回数组中前 n 个元素.)。

_.first = _.head = _.take = function(array, n, guard) {
  if (array == null || array.length < 1) return void 0;
  if (n == null || guard) return array[0];
  return _.initial(array, array.length - n);
};

1、 判断array为空时,返回void 0。

2 判断n为null或存在guard时,返回数组的第一个元素值。guard的存在是为了防止用户继续传入了第三个参数或以上无意义的参数。例:

“ _.map([[1, 2], [3, 4]], _.first)”

运行 _.map()函数时,将会有三个函数传进 _.first()函数:value,index,list。

3、 判断array存在且n存在时,运行_.initial()函数,返回数组0~(array.length - n)的元素值。

例:

var list = [3,5,7,2,8,2];
var test = _.first(list);
console.log(test);//3

var test2 = _.first(list,3);
console.log(test2);//[3, 5, 7]

var test3 = _.first(list,3,5);
console.log(test3);//3

2. _.initial

_.initial(array, [n]) 返回数组中除了最后一个元素外的其他全部元素。 在arguments对象上特别有用。传递 n参数将从结果中排除从最后一个开始的n个元素(愚人码头注:排除数组后面的 n 个元素)。

_.initial = function(array, n, guard) {
  return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
};

1、 若n不存在,则运行slice.call()函数,返回一个0~(array.length - 1)的数组。

2、 若n存在,则运行slice.call()函数,返回一个0~(array.length - n)的数组。

例:

var list = [3,5,7,2,8,2];
var test = _.initial(list);
console.log(test);//[3, 5, 7, 2, 8]

var test2 = _.initial(list,2);
console.log(test2);//[3, 5, 7, 2]

3. _.last

_.last(array, [n]) 返回array(数组)的最后一个元素。传递 n参数将返回数组中从最后一个元素开始的n个元素(愚人码头注:返回数组里的后面的n个元素)。

_.last = function(array, n, guard) {
  if (array == null || array.length < 1) return void 0;
  if (n == null || guard) return array[array.length - 1];
  return _.rest(array, Math.max(0, array.length - n));
};

1、 判断array为空时,返回void 0。

2、 判断n为null或存在guard时,返回数组的最后一个元素值。

3、 判断array存在且n存在时,运行_.rest()函数,返回数组(array.length - n)~array.length的元素值。

例:

var list = [3,5,7,2,8,2];
var test = _.last(list);
console.log(test);//2

var test2 = _.last(list,2);
console.log(test2);//[8, 2]

4. _.rest

_.rest(array, [index]) Alias: tail, drop 返回数组中除了第一个元素外的其他全部元素。传递 index 参数将返回从index开始的剩余所有元素 。

_.rest = _.tail = _.drop = function(array, n, guard) {
  return slice.call(array, n == null || guard ? 1 : n);
};

1、 若n不存在,则运行slice.call()函数,返回一个1~array.length的数组。

2、 若n存在,则运行slice.call()函数,返回一个n~array.length的数组。

例:

var list = [3,5,7,2,8,2];
var test = _.rest(list);
console.log(test);//[5, 7, 2, 8, 2]

var test2 = _.rest(list,2);
console.log(test2);//[7, 2, 8, 2]

5. _.compact

_.compact(array) 返回一个除去所有false值的 array副本。 在javascript中, false, null, 0, “”, undefined 和 NaN 都是false值.

_.compact = function(array) {
  return _.filter(array, Boolean);
};

1、 根据上面的代码,可以认为 _.compact()与 _.filter()函数等价,即:

_.compact = _.filter(array);
			 =function(obj, predicate, context) {
  var results = [];
  predicate = cb(predicate, context);
  _.each(obj, function(value, index, list) {
    if (predicate(value, index, list)) results.push(value);
  });
  return results;
};

2、 运行 _.filter()函数,得到predicate= _.identity

3、 运行 _.each()函数,遍历array并返回array中的真值。

例:

var list = [0, 1, false, 2, '', 3, undefined , NaN, 'NaN', 'undefined'];
var test = _.compact(list);
console.log(test);//[1, 2, 3, 'NaN', 'undefined']

6. _.flatten

_.flatten(array, [shallow]) 将一个嵌套多层的数组 array(数组) (嵌套可以是任何层数)转换为只有一层的数组。 如果你传递 shallow参数,数组将只减少一维的嵌套。

var flatten = function(input, shallow, strict, output) {
  output = output || [];
  var idx = output.length;
  for (var i = 0, length = getLength(input); i < length; i++) {
    // _.isArguments(object) 
    // 如果object是一个参数对象,返回true。
    var value = input[i];
    if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
      // Flatten current level of array or arguments object.
      if (shallow) {
        var j = 0, len = value.length;
        while (j < len) output[idx++] = value[j++];
      } else {
        flatten(value, shallow, strict, output);
        idx = output.length;
      }
    } else if (!strict) {
      output[idx++] = value;
    }
  }
  return output;
};
_.flatten = function(array, shallow) {
  return flatten(array, shallow, false);
};

1、 运行flatten()函数。并传入三个参数:array,shallow,false。

2、 由于没有传入第四个参数,故output=[],idx=output.length。

3、 运行for循环函数,value等于数组input[i]中的值。

4、 判断value为类数组对象且value为数组或者为参数对象。

a)若是,则判断shallow是否为真,若为真,则运行while函数,把数组的下一级中的所有元素都赋值给output,并结束运行flatten()函数,返回output值;若为假,则继续运行flatten()函数,直到output称为一维数组为止。

b)若否,则判断第三个参数strict为否,则直接把value的值赋给output。即,若value的值为对象时,直接把对象赋值给output。

例:

var list = [1, [2], [3, [[4]]]];
var test = _.flatten(list);
console.log(test);//[1, 2, 3, 4]

var test2 = _.flatten(list,true);
console.log(test2);//[1, 2, 3, [[4]]]
var list3 = [5, 6, 7, 8];
var test3 = _.flatten(list3);
console.log(test3);//[5, 6, 7, 8]
var list4 = [
	{one:'a',two:'b'}, 
	6, 
	{three:'c'}, 
	8 , 
	[1,5,3],
	[3,[5]]
];
var test4 = _.flatten(list4);
console.log(test4);//[{one:'a',two:'b'}, 6, {three:'c'}, 8, 1, 5, 3, 3, 5]

7. _.without

_.without(array, *values) 返回一个删除所有values值后的 array副本。(愚人码头注:使用===表达式做相等测试。)

_.without = restArgs(function(array, otherArrays) {
  // _.difference(array, *others) 
  // 返回的值来自array参数数组,并且不存在于other 数组.
  return _.difference(array, otherArrays);
});

1、 运行restArgs()函数,并运行里面的function()函数。

2、 运行_.difference()函数,返回array参数中不存在otherArrays参数中的数组。

例:

var list = [1, 2, 1, 0, 3, 1, 4];
var test = _.without(list, 0, 1);
console.log(test);//[2, 3, 4]
var list2 = {
	one:'a',
	two:'b',
	three:'c',
	four:'d',
	five:'e'
};
var test2 = _.without(list2, 'b', 'd');
console.log(test2);//["a", "c", "e"]

8. _.uniq

_.uniq(array, [isSorted], [iteratee]) Alias: unique 返回 array去重后的副本, 使用 === 做相等测试. 如果您确定 array 已经排序, 那么给 isSorted 参数传递 true值, 此函数将运行的更快的算法. 如果要处理对象元素, 传递 iteratee函数来获取要对比的属性.

_.uniq = _.unique = function(array, isSorted, iteratee, context) {
  // _.isBoolean(object) 
  // 如果object是一个布尔值,返回true,否则返回false。
  if (!_.isBoolean(isSorted)) {
    context = iteratee;
    iteratee = isSorted;
    isSorted = false;
  }
  if (iteratee != null) iteratee = cb(iteratee, context);
  var result = [];
  var seen = [];
  for (var i = 0, length = getLength(array); i < length; i++) {
    var value = array[i],
        computed = iteratee ? iteratee(value, i, array) : value;
    if (isSorted) {
      if (!i || seen !== computed) result.push(value);
      seen = computed;
    } else if (iteratee) {
      // _.contains(list, value, [fromIndex]) 
      // 如果list包含指定的value则返回true(
      // 如果list 是数组,内部使用indexOf判断。
      // 使用fromIndex来给定开始检索的索引位置。
      if (!_.contains(seen, computed)) {
        seen.push(computed);
        result.push(value);
      }
    } else if (!_.contains(result, value)) {
      result.push(value);
    }
  }
  return result;
};

1、 判断isSorted若不为布尔值,则把迭代函数iteratee赋值给context,isSorted赋值给iteratee,isSorted的值为false。这是为了防止用户习惯性把迭代函数iteratee作为第二个参数,把context作为第三个参数传进函数。

2、 若iteratee不为空,则运行cb()函数。

3、 运行for函数,遍历数组。

4、 若存在iteratee函数,则先把数组传入iteratee函数,运行完成后赋值给computed,若不存在,则直接把数组值赋值给computed。

5、 若isSorted为真,!i 判断i为0时为真,其他数组为假。即,i为0时一定运行push函数。其他数字则通过判断seen是否不等于computed时,运行push函数。最后把computed赋值给seen。但运行此段代码的前提是,已知array是按照顺序排列的。

6、 若isSorted为假,则判断iteratee函数是否存在,若存在,则运行 _.contains()函数,若seen不包含指定的computed值,则运行push函数。

7、 若不存在iteratee函数,则运行 _.contains()函数,若result不包含指定的value值,则运行push函数。

8、 最后返回result的值。

例:

var list = [1, 2, 1, 3, 1, 4];
var test = _.uniq(list);
console.log(test);//[1, 2, 3, 4]
var list2 = [1, 2, 3, 3, 4, 5, 5, 6, 6];
var test2 = _.uniq(list2,true);
console.log(test2);//[1, 2, 3, 4, 5, 6]

9. _.union

_.union(*arrays) 返回传入的 arrays(数组)并集:按顺序返回,返回数组的元素是唯一的,可以传入一个或多个 arrays(数组)。

_.union = restArgs(function(arrays) {
  return _.uniq(flatten(arrays, true, true));
});

1、 运行restArgs()函数,并运行里面的function()函数。

2、 运行flatten()函数,传入数组arrays,并减少一维嵌套

3、 运行_.uniq()函数,把得到的array数组进行唯一值筛选,并返回最终值。

例:

var list = [1, 2, 3];
var list2 = [101, 2, 1, 10];
var list3 = [2, 1];
var test = _.union(list, list2, list3);
console.log(test);//[1, 2, 3, 101, 10]
var list5 = [1, [5,8], 3];
var list6 = [101, 2, 1, 10];
var list7 = [2, [1,7]];
var test2 = _.union(list5, list6, list7);
console.log(test2);//[1, [5,8], 3, 101, 2, 10, [1,7] ]
var list8 = [1, 2, 3];
var list9 = {one:'a'};
var list10 = [2, 1,7];
var test3 = _.union(list8, list9, list10);
console.log(test3);//[1, 2 , 3 ,7 ]

10. _.intersection

_.intersection(*arrays) 返回传入 arrays(数组)交集。结果中的每个值是存在于传入的每个arrays(数组)里。

_.intersection = function(array) {
  var result = [];
  var argsLength = arguments.length;
  for (var i = 0, length = getLength(array); i < length; i++) {
    // _.contains(list, value, [fromIndex]) 
    // 如果list包含指定的value则返回true(
    // 如果list 是数组,内部使用indexOf判断。
    // 使用fromIndex来给定开始检索的索引位置。
    var item = array[i];
    if (_.contains(result, item)) continue;
    var j;
    for (j = 1; j < argsLength; j++) {
      if (!_.contains(arguments[j], item)) break;
    }
    if (j === argsLength) result.push(item);
  }
  return result;
};

1、 先读取arguments参数数组的长度,并赋值给argsLength。

2、 运行for函数,把每个传入的array的值赋值给item。

3、 运行 _.contains()函数,若result包含指定的item值,则继续运行运行第一层for循环。

4、 若result不包含指定的item值,运行第二层for函数,运行 _.contains()函数,若array中其中一个item值不存在于arguments[j],则跳出第二层for循环。即证明item不是交集中的数据。

5、 若j完全与argsLength相等,则把item的值push到result中,即item的值都存在于其他的数组中。

例:

var list = [1, 2, 3];
var list2 = [101, 2, 1, 10];
var list3 = [2, 1];
var test = _.intersection(list, list2, list3);
console.log(test);//[1, 2]

11. _.difference

_.difference(array, *others) 类似于without,但返回的值来自array参数数组,并且不存在于other 数组.

_.difference = restArgs(function(array, rest) {
  rest = flatten(rest, true, true);
  return _.filter(array, function(value){
    return !_.contains(rest, value);
  });
});

1、 运行restAargs()函数,把others参数变为数组传进rest中。

2、 运行flatten()函数,把rest中的各个数组变成一维数组,并且值返回类型为数组的值。

3、 运行_.filter()函数和 _.contains()函数,把value不包含于rest的值组成一个数组并返回得到的值。

例:

var list = [1, 2, 3, 4, 5];
var test = _.difference(list, [5, 2, 10]);
console.log(test);//[1, 3, 4]
var list2 = {
	one:'a',
	two:'b',
	three:'c',
	four:'d',
	five:'e'
};
var test2 = _.difference(list2, ['b'], ['d']);
console.log(test2);//["a", "c", "e"]

12. _.unzip

_.unzip(arrays) 与zip功能相反的函数,给定若干arrays,返回一串联的新数组,其第一元素个包含所有的输入数组的第一元素,其第二包含了所有的第二元素,依此类推。通过apply用于传递数组的数组。

_.unzip = function(array) {
  var length = array && _.max(array, getLength).length || 0;
  var result = Array(length);

  for (var index = 0; index < length; index++) {
  	  // _.pluck(list, propertyName) 
    // pluck也许是map最常使用的用例模型的简化版本,
    // 即萃取数组对象中某属性值,返回一个数组。
    result[index] = _.pluck(array, index);
  }
  return result;
};

1、 运行_.max()函数,并找出array中子数组的最大长度,赋值给length。

a) 其中, _.max()函数中的iteratee函数为:

var property = function(key) {
  return function(obj) {
    return obj == null ? void 0 : obj[key];
  };
};
var getLength = property('length');
iteratee = getLength;

b) _.max()函数将运行下面的函数求出最大值:

_.each(obj, function(v, index, list) {
 computed = iteratee(v, index, list);
 if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
   result = v;
   lastComputed = computed;
 }
});

2、 运行for循环函数,并运行_.pluck()函数,得到array数组中各子数组的相应index的值,并赋值给result[index]。

3、 返回result的值。

例:

var list = [
	["moe", 30, true], 
	["larry", 40, false], 
	["curly", 50, false]
];
var test = _.unzip(list);
console.log(test);
/*
[
	['moe', 'larry', 'curly'], 
	[30, 40, 50], 
	[true, false, false]
]
*/
var list2 = [
	['moe', 'larry', 'curly'],
	[30, 40, 50],
	[true, false, false]
];
var test2 = _.unzip(list2);
console.log(test2);
/*
[
	["moe", 30, true], 
	["larry", 40, false], 
	["curly", 50, false]
]
*/
var list3 = [
	["moe", 30, true], 
	["larry", 40, false,'run'], 
	["curly", 50, false]
];
var test3 = _.unzip(list3);
console.log(test3);
/*
[
	['moe', 'larry', 'curly'], 
	[30, 40, 50], 
	[true, false, false],
	[undefined, 'run', undefined]
]
*/

13. _.zip

_.zip(*arrays) 将 每个arrays中相应位置的值合并在一起。在合并分开保存的数据时很有用. 如果你用来处理矩阵嵌套数组时, _.zip.apply 可以做类似的效果。

_.zip = restArgs(_.unzip);

1、 先运行restArgs()函数,把多个数组合并为一个数组。

2、 运行_.unzip函数。得到result结果。

3、 _.zip()函数与 _.unzip()函数的最大区别是: _.zip()函数能传入的多个参数。 _.unzip()函数只能传入一个参数。

例:

var list = ['moe', 'larry', 'curly'];
var list2 = [30, 40, 50];
var list3 = [true, false, false];
var test = _.zip(list,list2,list3);
console.log(test);
/*
[
	["moe", 30, true], 
	["larry", 40, false], 
	["curly", 50, false]
]
*/
var list4 = ["moe", 30, true];
var list5 = ["larry", 40, false]; 
var list6 = ["curly", 50, false];
var test2 = _.zip(list4,list5,list6);
console.log(test2);
/*
[
	['moe', 'larry', 'curly'], 
	[30, 40, 50], 
	[true, false, false]
]
*/

14. _.object

_.object(list, [values]) 将数组转换为对象。传递任何一个单独[key, value]对的列表,或者一个键的列表和一个值得列表。 如果存在重复键,最后一个值将被返回。

_.object = function(list, values) {
  var result = {};
  for (var i = 0, length = getLength(list); i < length; i++) {
    if (values) {
      result[list[i]] = values[i];
    } else {
      result[list[i][0]] = list[i][1];
    }
  }
  return result;
};

1、 运行getLength函数,得到list的长度。

2、 运行for函数,且运行次数为list的长度值。

3、 判断是否存在values:

a) 若存在,则把values[i]的值赋值给result[list[i]]。其中list[i]为result的key,values[i]为result相应key的值。

例:

var list1 = ['moe', 'larry', 'curly'];
var list2 = [30, 40, 50,60];
var test = _.object(list1,list2);
console.log(test);
/*
{moe: 30, larry: 40, curly: 50}

b) 若不存在,则把二维数组中,list[i][1]的值赋值给result[list[i][0]]。其中list[i][0]为result的key,list[i][1]为result相应key的值。

例:

var list3 = [
	['moe', 30],
	['larry', 40],
	['curly', 50]
];
var test2 = _.object(list3);
console.log(test2);
/*
{moe: 30, larry: 40, curly: 50}
*/

15. _.findIndex

_.findIndex(array, predicate, [context]) 类似于 _.indexOf,当predicate通过真检查时,返回第一个索引值;否则返回-1。

var createPredicateIndexFinder = function(dir) {
  return function(array, predicate, context) {
    predicate = cb(predicate, context);
    var length = getLength(array);
    var index = dir > 0 ? 0 : length - 1;
    for (; index >= 0 && index < length; index += dir) {
      if (predicate(array[index], index, array)) return index;
    }
    return -1;
  };
};
_.findIndex = createPredicateIndexFinder(1);

1、 运行createPredicateIndexFinder()函数,并传入参数1。

2、 运行function,并传入参数array、predicate、context。

3、 得到迭代函数predicate的值:

predicate=optimizeCb(predicate,context);
			=function(value, index, collection) {
      			return predicate.call(context, value, index, collection);
   		};

4、 index从0开始进行for循环,当满足迭代函数predicate的条件时,直接返回index(索引位置),若遍历完列表后,没有满足迭代函数predicate条件,则返回-1。

例:

var list = [4, 6, 8, 12];
var test = _.findIndex(list,function(value){
	return value == 7;
});
console.log(test);//-1 // not found
var list2 = [4, 6, 7, 12];
var test2 = _.findIndex(list2,function(value){
	return value == 7;
});
console.log(test2);//2
var list = [
 	{'id': 1, 'name': 'Bob', 'last': 'Brown'},
 	{'id': 2, 'name': 'Ted', 'last': 'White'},
 	{'id': 3, 'name': 'Frank', 'last': 'James'},
 	{'id': 4, 'name': 'Ted', 'last': 'Jones'}
];
var test = _.findIndex(list,{
  	name: 'Ted'
});
console.log(test);//1

16. _.findLastIndex

_.findLastIndex(array, predicate, [context]) 和 _.findIndex类似,但反向迭代数组,当predicate通过真检查时,最接近末端的索引值将被返回。

_.findLastIndex = createPredicateIndexFinder(-1);

1、 实现方法与 _.findIndex()函数一样,先运行createPredicateIndexFinder()函数,唯一的不同是传入了参数-1。其参数影响了for循环时是从左往右,或从右往左遍历数组。

例:

var list = [
 	{'id': 1, 'name': 'Bob', 'last': 'Brown'},
 	{'id': 2, 'name': 'Ted', 'last': 'White'},
 	{'id': 3, 'name': 'Frank', 'last': 'James'},
 	{'id': 4, 'name': 'Ted', 'last': 'Jones'}
];
var test = _.findLastIndex(list,{
  	name: 'Ted'
});
console.log(test);//3
var list2 = [
	{age:34,name:'aa'},
	{age:56,name:'bb'},
	{age:73,name:'cc'},
	{age:42,name:'dd'},
];
var test2 = _.findLastIndex(list2,function (value){
	return value.age == 73;
});
console.log(test2);//2

17. _.sortedIndex

_.sortedIndex(list, value, [iteratee], [context]) 使用二分查找确定value在list中的位置序号,value按此序号插入能保持list原有的排序。如果提供iterator函数,iterator将作为list排序的依据,包括你传递的value 。iterator也可以是字符串的属性名用来排序(比如length)。

_.sortedIndex = function(array, obj, iteratee, context) {
  iteratee = cb(iteratee, context, 1);
  var value = iteratee(obj);
  var low = 0, high = getLength(array);
  while (low < high) {
  	  //math.floor(x)返回小于参数x的最大整数,即对浮点数向下取整
    var mid = Math.floor((low + high) / 2);
    if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
  }
  return low;
};

1、 运行cb()函数

a) 由于cb中的第三个参数argCount为1 ,故若iteratee为函数时,得到iteratee的值为:

iteratee = cb(iteratee, context, 1)
			 = function(value) {
	return func.call(context, value);
};

b) 若iteratee为字符串,则

iteratee=_.property(value);

2、 得到value的值,并定义low索引最小值与high索引最大值。

3、 运行Math.floor()函数向下取整,二分法求的索引的中间值mid。

4、 判断索引中间值所在的array位置中iteratee(array[mid])的值是否小于value的值,若是,则low赋值为mid+1;若否,则high赋值为mid。切通过while()函数实现循环,知道满足条件low < high为止。并返回low的值。

例:

var list = [10, 20, 30, 40, 50];
var test = _.sortedIndex(list,35);
console.log(test);//3
var list2 =  [
	[2,4,6], 
	[6,2]
];
var test2 = _.sortedIndex(list2,[7,8], function(value){
	return value[0];
});
console.log(test2);//2

var test3 = _.sortedIndex(list2,[5,8]);
console.log(test3);//1

var test4 = _.sortedIndex(list2,[9,1],1);
console.log(test4);//0
var list3 =  [
	{name: 'moe', age: 40}, 
	{name: 'curly', age: 60}
];
var test5 = _.sortedIndex(list3,{name: 'larry', age: 50}, 'age');
console.log(test5);//1

var test6 = _.sortedIndex(list3,{name: 'larry', age: 50}, function(value){
	return value.age;
});
console.log(test6);//1

18. _.indexOf

_.indexOf(array, value, [isSorted]) 返回value在该 array 中的索引值,如果value不存在 array中就返回-1。使用原生的indexOf 函数,除非它失效。如果您正在使用一个大数组,你知道数组已经排序,传递true给isSorted将更快的用二进制搜索..,或者,传递一个数字作为第三个参数,为了在给定的索引的数组中寻找第一个匹配值。

var createIndexFinder = function(dir, predicateFind, sortedIndex) {
  return function(array, item, idx) {
    var i = 0, length = getLength(array);
    if (typeof idx == 'number') {
      if (dir > 0) {
        i = idx >= 0 ? idx : Math.max(idx + length, i);
      } else {
        length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
      }
    } else if (sortedIndex && idx && length) {
      idx = sortedIndex(array, item);
      return array[idx] === item ? idx : -1;
    }
    if (item !== item) {
      // _.isNaN(object) 
      // 如果object是 NaN,返回true。 
      // 注意: 这和原生的isNaN 函数不一样,
      // 如果变量是undefined,原生的isNaN 函数也会返回 true 。
      // Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组
      // 请使用 isNaN() 来判断一个值是否是数字。原因是 NaN 与所有值都不相等,包括它自己。
      idx = predicateFind(slice.call(array, i, length), _.isNaN);
      return idx >= 0 ? idx + i : -1;
    }
    for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
      if (array[idx] === item) return idx;
    }
    return -1;
  };
};
_.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);

1、 运行createIndexFinder()函数。传入三个参数:1、_.findIndex、 _.sortedIndex。

2、 运行function函数,传入三个参数:array(array), value(item), isSorted(idx)。

3、 判断isSorted(idx)参数是否传入数字类型的值。

a) 若是,在这里dir为1大于0,判断idx大于等于0时,i的值为idx,若idx小于0,则取idx加上array的长度,与i的最大值。如idx为-3,length为6 ,i原始值为0 ,则i=3。

b) 若否,则判断isSorted(idx)参数是否传入true布尔变,且sortedIndex的值是否存在。若是,则运行sortedIndex()函数,用二分法的方式,把idx找出来,并判断array[idx]的值是否完全等于value(item)的值,若是,直接结束函数的运行,并返回idx的值,若否,则结束函数的运行,并返回-1值。

c) isSorted(idx)参数的传入,主要作用是运用了二分法,节省查找时间。

4、 若函数继续运行,则判断item是否为NaN,因为NaN与所有值都不相等,包括它自己。只能使用isNaN()来判断一个值是否是数字。然后运行predicateFind()(_.findIndex)函数。若满足 _.isNaN()函数条件,则把得到的索引值传给idx,若不满足,则idx等于-1,并结束函数的运行,并返回idx的值。

5、 若函数继续运行,则运行for函数,并通过条件array[idx] === item,找出idx,并返回。若不存在idx,则返回-1。

例:

var list = [1, 2, 3];
var test = _.indexOf(list,2);
console.log(test);//1
var list2 = [1, 2, 3, 4, 5, 6];
var test2 = _.indexOf(list2,2,3);
console.log(test2);//-1

var test3 = _.indexOf(list2,2,-5);
console.log(test3);//1

var test4 = _.indexOf(list2,4,true);
console.log(test4);//3
var list5 = {
	'0':'a',
	'1':'b',
	'2':'c',
	'3':'d',
	'4':'e',
	length:'4'
};
var test5 = _.indexOf(list5,'d');
console.log(test5);//3
var list6 = [1,5,6,undefined,2,6,NaN,2,5];
var test6 = _.indexOf(list6,NaN);
console.log(test6);//6

var test7 = _.indexOf(list6,undefined);
console.log(test7);//3

19. _.lastIndexOf

_.lastIndexOf(array, value, [fromIndex]) 返回value在该 array 中的从最后开始的索引值,如果value不存在 array中就返回-1。如果支持原生的lastIndexOf,将使用原生的lastIndexOf函数。传递fromIndex将从你给定的索性值开始搜索。

_.lastIndexOf = createIndexFinder(-1, _.findLastIndex);

1、 运行createIndexFinder()函数。传入辆个参数:-1、_.findLastIndex。

2、 运行function函数,传入三个参数:array(array), value(item), fromIndex(idx)。

3、 判断fromIndex(idx)参数是否传入数字类型的值。

a) 若是,在这里dir为-1小于0,判断idx大于等于0时,i的值为idx+1,与array的长度的最小值。如idx为3,length为6 ,则i=4。若idx小于0,则i的值为idx+length+1。如idx为-4,length为6 ,则i=3。

b) 若否,这里与 _.indexOf不同,尽管fromIndex(idx)参数传入true布尔变量,当时sortedIndex不存在,故不使用二分法。

c) fromIndex(idx)参数的传入,主要作用是从你给定的索性值开始搜索,节省查找时间。

4、 若函数继续运行,则判断item是否为NaN,因为NaN与所有值都不相等,包括它自己。只能使用isNaN()来判断一个值是否是数字。然后运行predicateFind()(_.findLastIndex)函数。若满足 _.isNaN()函数条件,则把得到的索引值传给idx,若不满足,则idx等于-1,并结束函数的运行,并返回idx的值。

5、 若函数继续运行,则运行for函数,并通过条件array[idx] === item,找出idx,并返回。若不存在idx,则返回-1。

例:

var list = [1, 2, 3, 1, 2, 3];
var test = _.lastIndexOf(list,2);
console.log(test);//4

console.log('----------------------------------');

var test2 = _.lastIndexOf(list,2,true);
console.log(test2);//4
var list2 = [1, 2, 3, 4, 2, 6];
var test3 = _.lastIndexOf(list2,2,3);
console.log(test3);//1
var list3 = [1, 2, 3, 4, 4, 6];
var test4 = _.lastIndexOf(list3,4,-3);
console.log(test4);//3

20. _.range

_.range([start], stop, [step]) 一个用来创建整数灵活编号的列表的函数,便于each 和 map循环。如果省略start则默认为 0;step 默认为 1.返回一个从start 到stop的整数的列表,用step来增加 (或减少)独占。值得注意的是,如果stop值在start前面(也就是stop值小于start值),那么值域为负增长。

_.range = function(start, stop, step) {
  if (stop == null) {
    stop = start || 0;
    start = 0;
  }
  if (!step) {
    step = stop < start ? -1 : 1;
  }
	// math.ceil(x)返回大于参数x的最小整数,即对浮点数向上取整.
  var length = Math.max(Math.ceil((stop - start) / step), 0);
  var range = Array(length);

  for (var idx = 0; idx < length; idx++, start += step) {
    range[idx] = start;
  }

  return range;
};

1、 运行function()函数,并传入三个参数:start、stop、step。

2、 判断第二个参数stop为空时,把第一个参数start或0赋值给stop,把0赋值给start。即相当于用户没有传入start的值,start的默认值为0。

3、 判断第三个参数没有传入,则若stop小于start,则step的值为-1 ,若stop大于等于start,则step的值为1。

4、 运行Math.ceil()函数,求出用户要求需要返回的值的长度,并与0比较,运行Math.max()函数,求出长度的最大值。

5、 运行for函数,start=start+step,并把start传递给range[idx],最后返回range。

例:

var test = _.range(10);
console.log(test);
//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

console.log('-----------------------');

var test = _.range(1, 11);
console.log(test);
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

console.log('-----------------------');

var test = _.range(0, 30, 5);
console.log(test);
//[0, 5, 10, 15, 20, 25]

console.log('-----------------------');

var test = _.range(0, -10, -1);
console.log(test);
//[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

console.log('-----------------------');

var test = _.range(3, 0);
console.log(test);
//[3, 2, 1]

console.log('-----------------------');

var test = _.range(-1,-5);
console.log(test);
//[-1, -2, -3, -4]

console.log('-----------------------');

var test = _.range(0);
console.log(test);
//[]

21. _.chunk

_.chunk(array,count) 传入数组array,并按照count传入的数字,每count个为一组,组成一个新的二维数组。 若不传count,或count小于1,则得到一个空的数组。

_.chunk = function(array, count) {
  if (count == null || count < 1) return [];

  var result = [];
  var i = 0, length = array.length;
  while (i < length) {
    result.push(slice.call(array, i, i += count));
  }
  return result;
};

1、 判断count是否为空,或是否小于1,则返回空数组。

2、 运行while()循环函数,当满足条件i < length时,运行slice.call()函数,并从i开始,至i+count的数组都push,到result中,且更新i的值。

3、 最后把返回result。

例:

var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var test = _.chunk(list,4);
console.log(test);
/*
[
	[0, 1, 2, 3], 
	[4, 5, 6, 7], 
	[8, 9]
]
*/

var test3 = _.chunk(list,-1);
console.log(test3);//[]
var list2 = [
	{name:'a'},
	{name:'b'},
	{name:'c'},
	{name:'d'},
	{name:'e'},
	{name:'f'},
	{name:'g'},
	{name:'h'},
	{name:'i'},
	{name:'j'},
];
var test2 = _.chunk(list2,3);
console.log(test2);
/*
[
	[{name:'a'},{name:'b'},{name:'c'}], 
	[{name:'d'},{name:'e'},{name:'f'}], 
	[{name:'g'},{name:'h'},{name:'i'}],
	[{name:'j'}]
]
*/
Loading Disqus comments...