Lodash源码阅读-initCloneArray

Lodash 源码阅读-initCloneArray

概述

initCloneArray 是 Lodash 内部用于初始化数组克隆的函数,主要用于创建一个与原数组相同长度的新数组,并且当原数组具有特定属性(如通过正则表达式匹配产生的数组属性)时,会将这些特定属性也复制到新数组中。

前置学习

依赖函数

  • 无直接依赖函数

相关技术知识

  • JavaScript 数组构造器(Array Constructor)
  • RegExp.exec() 方法产生的结果数组的特殊属性
  • JavaScript 对象属性的检测与复制
  • hasOwnProperty 方法的使用

源码实现

js 复制代码
/**
 * Initializes an array clone.
 *
 * @private
 * @param {Array} array The array to clone.
 * @returns {Array} Returns the initialized clone.
 */
function initCloneArray(array) {
  var length = array.length,
    result = new array.constructor(length);

  // Add properties assigned by `RegExp#exec`.
  if (
    length &&
    typeof array[0] == "string" &&
    hasOwnProperty.call(array, "index")
  ) {
    result.index = array.index;
    result.input = array.input;
  }
  return result;
}

实现思路

initCloneArray 函数的实现思路比较简单:

  1. 首先获取原数组的长度
  2. 使用原数组的构造器创建一个相同长度的新数组(这样可以保证克隆结果与原数组类型一致)
  3. 然后检查是否需要复制 RegExp.exec() 方法产生的特殊属性:
    • 检查数组长度是否大于 0
    • 检查数组第一个元素是否为字符串类型
    • 检查数组是否有自己的 'index' 属性(RegExp.exec() 结果特有)
  4. 如果满足上述条件,则将原数组的 index 和 input 属性复制到新数组中
  5. 最后返回初始化后的克隆数组

源码解析

获取原数组长度并创建新数组

js 复制代码
var length = array.length,
  result = new array.constructor(length);

这里使用 array.constructor 而不是直接使用 Array 构造函数,是为了保证创建的新数组与原数组具有相同的类型。这在处理类数组对象或特殊数组(如 TypedArray)时特别重要。

示例:

js 复制代码
// 普通数组
const arr1 = [1, 2, 3];
const newArr1 = new arr1.constructor(arr1.length); // 等同于 new Array(3)

// 类型化数组
const arr2 = new Uint8Array([1, 2, 3]);
const newArr2 = new arr2.constructor(arr2.length); // 创建 Uint8Array 而非普通数组

复制 RegExp.exec() 的特殊属性

js 复制代码
if (
  length &&
  typeof array[0] == "string" &&
  hasOwnProperty.call(array, "index")
) {
  result.index = array.index;
  result.input = array.input;
}

这段代码处理的是当数组来自 RegExp#exec() 方法调用的特殊情况。

当使用正则表达式的 exec 方法匹配字符串时,返回的数组会带有两个特殊属性:

  • index: 表示匹配的文本在原字符串中的位置
  • input: 表示原始的字符串

下面是一个例子:

js 复制代码
const regex = /c/;
const result = regex.exec("abcde");
console.log(result); // ['c', index: 2, input: 'abcde', groups: undefined]
console.log(result.index); // 2
console.log(result.input); // 'abcde'

函数通过三个条件来判断是否为 exec 结果:

  1. 数组长度大于 0(length
  2. 第一个元素是字符串(typeof array[0] == 'string'
  3. 数组拥有自己的 index 属性(hasOwnProperty.call(array, 'index')

如果满足这些条件,就将原数组的 indexinput 属性复制到新数组中,以保持这些特殊属性。

应用场景

在 Lodash 内部的应用

initCloneArray 主要用在 Lodash 的 clonecloneDeep 方法内部,是 baseClone 函数的一部分。当需要克隆数组类型的值时,会使用该函数初始化克隆结果:

js 复制代码
// 在 baseClone 函数中的应用
if (isArr) {
  result = initCloneArray(value);
  if (!isDeep) {
    return copyArray(value, result);
  }
}

如果不是进行深度克隆,会在初始化数组后通过 copyArray 函数复制数组元素。如果是深度克隆,则会在后续代码中递归处理每个数组元素。

总结

initCloneArray 函数虽然短小,但体现了 Lodash 源码的几个核心设计思想:

  1. 类型保持:通过使用原对象的构造器而不是硬编码的 Array 构造函数,确保克隆结果与原始数据类型一致
  2. 特殊情况处理:识别并处理 RegExp.exec() 结果这种特殊情况,保证克隆的完整性
  3. 职责单一:该函数只负责初始化数组克隆,不负责复制数组元素内容,符合单一职责原则

这种精细的类型处理和特殊情况的考虑,是 Lodash 库稳定性和适用性广泛的重要原因之一。在我们自己实现工具函数时,也应当学习这种严谨和全面的思考方式。

相关推荐
前端小巷子19 分钟前
Web开发中的文件上传
前端·javascript·面试
翻滚吧键盘1 小时前
{{ }}和v-on:click
前端·vue.js
上单带刀不带妹1 小时前
手写 Vue 中虚拟 DOM 到真实 DOM 的完整过程
开发语言·前端·javascript·vue.js·前端框架
前端风云志1 小时前
typescript结构化类型应用两例
javascript
杨进军2 小时前
React 创建根节点 createRoot
前端·react.js·前端框架
ModyQyW2 小时前
用 AI 驱动 wot-design-uni 开发小程序
前端·uni-app
说码解字2 小时前
Kotlin lazy 委托的底层实现原理
前端
gnip2 小时前
总结一期正则表达式
javascript·正则表达式
爱分享的程序员3 小时前
前端面试专栏-算法篇:18. 查找算法(二分查找、哈希查找)
前端·javascript·node.js
翻滚吧键盘3 小时前
vue 条件渲染(v-if v-else-if v-else v-show)
前端·javascript·vue.js