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

相关推荐
用户69371750013841 小时前
Google 正在“收紧侧加载”:陌生 APK 安装或需等待 24 小时
android·前端
蓝帆傲亦1 小时前
Web 前端搜索文字高亮实现方法汇总
前端
用户69371750013841 小时前
Room 3.0:这次不是升级,是重来
android·前端·google
漫随流水2 小时前
旅游推荐系统(view.py)
前端·数据库·python·旅游
踩着两条虫4 小时前
VTJ.PRO 核心架构全公开!从设计稿到代码,揭秘AI智能体如何“听懂人话”
前端·vue.js·ai编程
jzlhll1235 小时前
kotlin Flow first() last()总结
开发语言·前端·kotlin
用头发抵命5 小时前
Vue 3 中优雅地集成 Video.js 播放器:从组件封装到功能定制
开发语言·javascript·ecmascript
蓝冰凌5 小时前
Vue 3 中 defineExpose 的行为【defineExpose暴露ref变量】详解:自动解包、响应性与实际使用
前端·javascript·vue.js
奔跑的呱呱牛6 小时前
generate-route-vue基于文件系统的 Vue Router 动态路由生成工具
前端·javascript·vue.js