Where is JavaScript?

lodash源码研析-数组分久必合concat

我愿在心与心之间架起一道小桥,哪怕只是几块垫脚的青石板也好,将我们琐屑凌乱的生命连接。
----<破解幸福密码>

介绍

concat 函数类似于 ES 规范中的函数作用,用于进行数组拼接。
只是 lodash 在实现的过程中,不断践行自建基石的方针,也做了一些判断处理。

依赖

数组拷贝 copyArray

这个方法被用到,主要是考虑对原数组的保护。

              
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
/** * 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 = Array(length)); while (++index < length) { array[index] = source[index]; } return array; } module.exports = copyArray;

数组后推入 arrayPush

继续自创push操作,通过操作数组下标进行赋值。

              
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
/** * Appends the elements of `values` to `array`. * * @private * @param {Array} array The array to modify. * @param {Array} values The values to append. * @returns {Array} Returns `array`. */ function arrayPush(array, values) { var index = -1, length = values.length, offset = array.length; while (++index < length) { array[offset + index] = values[index]; } return array; } module.exports = arrayPush;

基础的数组扁平化操作 baseFlatten :point_left: (划重点啦)

明显数组和类数组的 arguments 对象,可以通过遍历来展平。
另外在 ES6 中,可以设置 Symbol.isConcatSpreadable 的属性来表示该对象是否可以被展平。 Symbol.isConcatSpreadable 的值如果被设置为真值时,该对象是可以被展平的。

              
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
let b = {0: 1, 1: 2, length: 2} b[Symbol.isConcatSpreadable] // undefined, 默认无定义 console.log([].concat(b)) // [{…}],没取出其中元素 b[Symbol.isConcatSpreadable] = true console.log([].concat(b)) // [1, 2],可以被展平
              
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
var arrayPush = require('./_arrayPush'), // 可扁平化判断 isFlattenable = require('./_isFlattenable'); /** * The base implementation of `_.flatten` with support for restricting flattening. * * @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. */ function baseFlatten(array, depth, predicate, isStrict, result) { var index = -1, length = array.length; predicate || (predicate = isFlattenable); // 预检查函数,不传指定为 isFlattenable result || (result = []); // 期望放到指定的数组里,不传默认为一个空数组 while (++index < length) { var value = array[index]; if (depth > 0 && predicate(value)) { if (depth > 1) { // 递归扁平化操作 // Recursively flatten arrays (susceptible to call stack limits). baseFlatten(value, depth - 1, predicate, isStrict, result); } else { arrayPush(result, value); } } else if (!isStrict) { // 非严格模式下,只做一层扁平化 result[result.length] = value; } } return result; } module.exports = baseFlatten;

源码

              
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
/** * Creates a new array concatenating `array` with any additional arrays * and/or values. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to concatenate. * @param {...*} [values] The values to concatenate. * @returns {Array} Returns the new concatenated array. * @example * * var array = [1]; * var other = _.concat(array, 2, [3], [[4]]); * * console.log(other); * // => [1, 2, 3, [4]] * * console.log(array); * // => [1] */ function concat() { var length = arguments.length; if (!length) { return []; } // 赋值已保护传入参数 var args = Array(length - 1), array = arguments[0], index = length; while (index--) { args[index - 1] = arguments[index]; } // 对参数列表做了一级扁平化处理 return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); } module.exports = concat;

总结

  • lodash 工具函数充分考虑了对传入参数的保护,尽可能小的影响参数。
  • lodash 通过一些选项判断赋予函数更高的自由度和容错率。

引用

本文使用「 署名 4.0 国际」创作共享协议。
本文同步发布于Littlewin's Blog,欢迎多多交流。

本文于 2018-4-17  发布在  Notes  分支,

并被添加「 源码研析 」标签

本站使用「 署名 4.0 国际」创作共享协议