天天一个lodash方法-concat

腱鞘炎犯了。第三天就没坚持住,罪过罪过。javascript

concat源码连接java

功能

建立一个用任何数组 或 值链接的新数组。git

使用方法

* var array = [1];
 * var other = _.concat(array, 2, [3], [[4]]);
 *
 * console.log(other);
 * // => [1, 2, 3, [4]]
 *
 * console.log(array);
 * // => [1]

注意,会返回一个新数组,而且不改变传入的数组。github

源码分析

源码里有100多行,显着有点乱,可是读下来,仍是有不少值得思考的地方。chrome

var MAX_SAFE_INTEGER = 9007199254740991;express

JS中Number类型的最大值,2的32次幂指-1npm


/** `Object#toString` result references. */
var argsTag = '[object Arguments]',
    funcTag = '[object Function]',
    genTag = '[object GeneratorFunction]';

在js中判断类型咱们能够借用Object.prototype.toString方法来判断类型。 下边是demo数组

var toString =Object.prototype.toString
var a = function(){console.log(toString.call(arguments))}
// [object Arguments]

link闭包

var root = freeGlobal || freeSelf || Function('return this')();

这里我比较注意的Function('return this')(),我在chrome里执行这段代码,返回的是全局对象。函数

经过google查到了缘由。

Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was called. This is different from using eval with code for a function expression.

使用Function构造函数建立的函数不会建立对其建立上下文的闭包;他们老是在全局建立。执行时,它们只能访问它们本身的局部变量和全局变量,而不能访问函数构造函数调用的范围。这与使用eval解析函数表达式的代码不一样。

link


arrayPushconcat中用到的工具方法。他接收两个数组,返回一个新的数组。

function arrayPush(array, values) {
  var index = -1,
      length = values.length, //传入的数组长度
      offset = array.length; //偏离值,values并入array,固然要从array的最后一位往里传。

  while (++index < length) { // loop 操做。
    array[offset + index] = values[index];
  }
  return array;
}

arrayPush([1,2,3],[4,5,6])

//[1, 2, 3, 4, 5, 6]

var objectProto = Object.prototype; //保留Object.prototype的引用。

var hasOwnProperty = objectProto.hasOwnProperty; // 这个方法判断是不是该对象上的自建属性,而不是prototype上的。

var objectToString = objectProto.toString; //保留引用。加快访问该方法的速度

/**
 * The base implementation of `_.flatten` with support for restricting flattening.
 *  _.flatten的基本实现方法
 * @private
 * @param {Array} array The array to flatten. // 须要被打平的数组。
 * @param {number} depth The maximum recursion depth. // 最大的递归深度。
 * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
 * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
 * @param {Array} [result=[]] The initial result value.// 指望放到指定的数组里,不传默认为一个空数组。
 * @returns {Array} Returns the new flattened array.//返回一个新的被扁平化的数组
 */
// 传入的方式 baseFlatten([[1,2,3,4,],1],1,false) =>

function baseFlatten(array, depth, predicate, isStrict, result) {
  var index = -1, //初使下标
      length = array.length;//须要被扁平的长度 => 2

  predicate || (predicate = isFlattenable);// 这里貌似只能传false,或者一个方法  => isFlattenable
  result || (result = []); // result => []

  while (++index < length) {
    var value = array[index]; // 0: [1,2,3,4]  depth:1   1: 1, 从1的位置就走到else if里了。
    if (depth > 0 && predicate(value)) {//predicate(value)  返回true or false,默认状况下是用来判断value是不是可被打平的。  depath 若是是2的话,就会将更高阶的数组打平,而后递归调用而传入result。
      if (depth > 1) {
        // Recursively flatten arrays (susceptible to call stack limits).
        baseFlatten(value, depth - 1, predicate, isStrict, result);
      } else {
        arrayPush(result, value); //arrayPush([],[1,2,3,4]) => result=[1,2,3,4]
      }
    } else if (!isStrict) {
      result[result.length] = value;
    }
  }
  return result;
}

/**
 * Checks if `value` is a flattenable `arguments` object or array.
 * 返回传入的value 是不是一个能够被打平的 arguments 对象或者数组
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
 */
function isFlattenable(value) {
  return isArray(value) || isArguments(value) ||
    !!(spreadableSymbol && value && value[spreadableSymbol]);
}

正主concat来了

//concat([1,2,3,4],[5,6,7,8])
function concat() { 
  var length = arguments.length, // 2
      args = Array(length ? length - 1 : 0),//arg = [empty]
      array = arguments[0],// [1,2,3,4]
      index = length;//2

  while (index--) {
    // 1
    args[index - 1] = arguments[index];   }
  // args[0]= [1,2,3,4] args[-1]=[5,6,7,8]
  return length
    ? arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1))
    : [];
}
//isArray(array) ? copyArray(array) : [array] =>   [1,2,3,4]
//baseFlatten(args, 1) => [5,6,7,8]
// return这里就成了 arrayPush([1,2,3,4],[5,6,7,8]) => [1,2,3,4,5,6,7,8]

/**
 * Copies the values of `source` to `array`.
 *
 * @private
 * @param {Array} source The array to copy values from.
 * @param {Array} [array=[]] The array to copy values to.
 * @returns {Array} Returns `array`.
 */
function copyArray(source, array) {
  var index = -1,
      length = source.length;

  array || (array = Array(length)); // array 不存在就建立一个和source长度同样的数组
  while (++index < length) {
    array[index] = source[index]; // 赋值进去,返回copy的数组,不改变原有的数组
  }
  return array;
}
相关文章
相关标签/搜索