underscore.js源碼解析【數組】

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

  // Get the first element of an array. Passing **n** will return the first N
  // values in the array. Aliased as `head` and `take`. The **guard** check
  // allows it to work with `_.map`.
  /*
    返回array(數組)的第一個元素。傳遞 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);
  };

  // Returns everything but the last entry of the array. Especially useful on
  // the arguments object. Passing **n** will return all the values in
  // the array, excluding the last N.
  /*
    返回數組中除了最後一個元素外的其餘所有元素。 在arguments對象上特別有用。傳遞 n參數將從結果中排除從最後一個開始的n個元素
  */
  _.initial = function(array, n, guard) {
    return slice.call(array, 0, Math.max(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.
  /*
    返回array(數組)的最後一個元素。傳遞 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));
  };

  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
  // Especially useful on the arguments object. Passing an **n** will return
  // the rest N values in the array.
  /*
    返回數組中除了第一個元素外的其餘所有元素。傳遞n參數將返回從n開始的剩餘全部元素 。
  */
  _.rest = _.tail = _.drop = function(array, n, guard) {
    return slice.call(array, n == null || guard ? 1 : n);
  };

  // Trim out all falsy values from an array.
  /*
    返回一個除去全部false值的array副本。 在javascript中, false, null, 0, "", undefined 和 NaN 都是false值.
  */
  _.compact = function(array) {
    return _.filter(array, Boolean);
  };

  // Internal implementation of a recursive `flatten` function.
  /*
    內部的flatten函數
  */
  var flatten = function(input, shallow, strict, output) {
    output = output || [];
    var idx = output.length;
    for (var i = 0, length = getLength(input); i < length; i++) {
      var value = input[i];
      // 若是value仍是數組或類數組
      // _.isArguments(value)實現原理是判斷value中是否有callee方法
      if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
        // Flatten current level of array or arguments object.
        //若是有shallow參數,則只打開一層
        if (shallow) {
          var j = 0, len = value.length;
          while (j < len) output[idx++] = value[j++];
        } else {// 不然,遞歸調用此函數,將結果數組output傳入
          flatten(value, shallow, strict, output);
          idx = output.length;
        }
      } else if (!strict) {
        output[idx++] = value;
      }
    }
    return output;
  };

  // Flatten out an array, either recursively (by default), or just one level.
  /*
    將一個嵌套多層的數組 array(數組) (嵌套能夠是任何層數)轉換爲只有一層的數組。 若是你傳遞 shallow參數,數組將只減小一維的嵌套。
  */
  _.flatten = function(array, shallow) {
    return flatten(array, shallow, false);
  };

  // Return a version of the array that does not contain the specified value(s).
  /*
    返回一個刪除全部values值後的 array副本。
  */
  _.without = restArgs(function(array, otherArrays) {
    return _.difference(array, otherArrays);
  });

  // 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`.
  /*
    返回 array去重後的副本, 若是您肯定 array 已經排序, 那麼給 isSorted 參數傳遞 true值, 此函數將運行的更快的算法. 若是要處理對象元素, 傳遞 iteratee函數來獲取要對比的屬性
  */
  _.uniq = _.unique = function(array, isSorted, iteratee, context) {
    // 若是沒有傳遞或傳遞的isSorted不爲布爾值,後面兩個參數前移
    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) {// 若是有iteratee函數,將值先push到seen中,再把value push到result中
        if (!_.contains(seen, computed)) {
          seen.push(computed);
          result.push(value);
        }
      } else if (!_.contains(result, value)) {
        result.push(value);
      }
    }
    return result;
  };

  // Produce an array that contains the union: each distinct element from all of
  // the passed-in arrays.
  /*
    返回傳入的 arrays(數組)並集:按順序返回,返回數組的元素是惟一的,能夠傳入一個或多個 arrays(數組)
  */
  _.union = restArgs(function(arrays) {
    return _.uniq(flatten(arrays, true, true));
  });

  // Produce an array that contains every item shared between all the
  // passed-in arrays.
  /*
    返回傳入 arrays(數組)交集。結果中的每一個值是存在於傳入的每一個arrays(數組)裏
    這個函數的效率是數組長度的乘積
  */
  _.intersection = function(array) {
    var result = [];
    var argsLength = arguments.length;
    for (var i = 0, length = getLength(array); i < length; i++) {
      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;
  };

  // Take the difference between one array and a number of other arrays.
  // Only the elements present in just the first array will remain.
  /*
    相似於without,但返回的值來自array參數數組,而且不存在於other 數組
  */
  _.difference = restArgs(function(array, rest) {
    rest = flatten(rest, true, true);
    return _.filter(array, function(value){
      return !_.contains(rest, value);// 用indexOf() > 0來判斷
    });
  });

  // Complement of _.zip. Unzip accepts an array of arrays and groups
  // each array's elements on shared indices.
  /*
    與zip功能相反的函數,給定若干arrays,返回一串聯的新數組,其第一元素個包含全部的輸入數組的第一元素,其第二包含了全部的第二元素,依此類推。
  */
  _.unzip = function(array) {
    var length = array && _.max(array, getLength).length || 0;// 返回數組中的元素的最長長度
    var result = Array(length);

    for (var index = 0; index < length; index++) {
      result[index] = _.pluck(array, index);// map(array, _.property(index))
    }
    return result;
  };

  // Zip together multiple lists into a single array -- elements that share
  // an index go together.
  /*
    將 每一個arrays中相應位置的值合併在一塊兒。在合併分開保存的數據時頗有用. 若是你用來處理矩陣嵌套數組時, _.zip.apply 能夠作相似的效果。
  */
  _.zip = restArgs(_.unzip);

  // Converts lists into objects. Pass either a single array of `[key, value]`
  // pairs, or two parallel arrays of the same length -- one of keys, and one of
  // the corresponding 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 {// 單獨的[key,value]對
        result[list[i][0]] = list[i][1];
      }
    }
    return result;
  };

  // Generator function to create the findIndex and findLastIndex functions.
  /*
    遍歷數組,找出符合predicate的項的index,找不到返回-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;
    };
  };

  // Returns the first index on an array-like that passes a predicate test.
  /*
    相似於_.indexOf
    和_.findIndex相似,但反向迭代數組
  */
  _.findIndex = createPredicateIndexFinder(1);
  _.findLastIndex = createPredicateIndexFinder(-1);

  // Use a comparator function to figure out the smallest index at which
  // an object should be inserted so as to maintain order. Uses binary search.
  /*
    使用二分查找肯定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) {// 二分查找
      var mid = Math.floor((low + high) / 2);
      if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
    }
    return low;
  };

  // Generator function to create the indexOf and lastIndexOf functions.
  /*
    求元素在數組中的位置
  */
  var createIndexFinder = function(dir, predicateFind, sortedIndex) {
    return function(array, item, idx) {
      var i = 0, length = getLength(array);
      if (typeof idx == 'number') {// 若是傳入了idx
        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) {// 若是沒傳入,可是數組有序,直接調用sortedIndex(array, item)
        idx = sortedIndex(array, item);
        return array[idx] === item ? idx : -1;
      }
      if (item !== item) {// 若是item爲NaN,說明要找出是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;
    };
  };

  // Return the position of the first occurrence of an item in an array,
  // or -1 if the item is not included in the array.
  // If the array is large and already in sort order, pass `true`
  // for **isSorted** to use binary search.
  /*
    返回value在該 array 中的索引值,若是value不存在 array中就返回-1。使用原生的indexOf 函數,除非它失效。若是您正在使用一個大數組,你知道數組已經排序,傳遞true給isSorted將更快的用二進制搜索..,或者,傳遞一個數字做爲第三個參數,爲了在給定的索引的數組中尋找第一個匹配值。
  */
  _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
  _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);

  // 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).
  /*
    一個用來建立整數靈活編號的列表的函數,便於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;
    }

    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;
  };

  // Split an **array** into several arrays containing **count** or less elements
  // of initial array.
  /*
    把數組arr從index=0處開始,分紅長度爲沒有重複部分的長度小於count的數組所組成的數組
  */
  _.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));// slice(s, e)方法當e大於數組最末尾位置時,返回從i到最後
    }
    return result;
  };
相關文章
相關標籤/搜索