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 库稳定性和适用性广泛的重要原因之一。在我们自己实现工具函数时,也应当学习这种严谨和全面的思考方式。

相关推荐
货拉拉技术4 分钟前
货拉拉开源Hadice:安卓 & 鸿蒙桌面调试工具
前端
程序猿DD44 分钟前
OctaFuse Gateway 2.11.0:流式请求优化、用户折扣策略与错误契约升级
前端·后端
尾善爱看海1 小时前
《JavaScript 数组操作全攻略:12 类 API + 30 个实战场景 + 20 个避坑指南》
前端·javascript·面试
计算机魔术师1 小时前
Anthropic 估值冲 4 万亿,但企业客户已经偷偷换了便宜模型
前端
OpsEye1 小时前
为什么你的 Agent 莫名烧钱?聊聊循环调用的兜底方案
javascript·ai编程
王六米。1 小时前
RAG知识库建设 文档解析 切分与索引如何衔接
服务器·前端·网络·企业数字化转型·智钳智能盒子
名字还没想好☜1 小时前
React 文件上传实战:预览 URL 回收、多文件逐个进度与拖拽放置区踩坑
前端·react·next.js
console.log('npc')1 小时前
06 — Model 层:数据模型与操作
前端·后端·node.js·express
linux_cfan2 小时前
16 · `custom-media-element`:属性拦截与转发
前端·javascript·音视频
右耳朵猫AI2 小时前
Web前端周刊2026W38 | React 19.3 发布、StyleX 深潜、jsdom 30.1 提速
前端·javascript·react.js·typescript·node.js