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

相关推荐
独立开阀者_FwtCoder2 分钟前
"页面白屏了?别慌!前端工程师必备的排查技巧和面试攻略"
java·前端·javascript
慧一居士3 分钟前
Vite 完整功能详解与 Vue 项目实战指南
前端·vue.js
南岸月明3 分钟前
不聊主业,聊聊你们眼中的副业是什么样的?
前端
Kevin在掘金920148 分钟前
c#、.net、Fluent UI Blazor
前端
LovelyAqaurius9 分钟前
RSA加密算法:从数学魔法到现实守护
前端
Hilaku10 分钟前
说实话,React的开发体验,已经被Vue甩开几条街了
前端·javascript·vue.js
星语卿11 分钟前
Js事件循环
javascript
datagear11 分钟前
如何在DataGear 5.4.1 中快速制作HTTP数据源服务端分页的数据表格看板
javascript·数据可视化
蛋黄蛋黄14 分钟前
微信表情怎么在自己的项目使用微信表情?-> [开源仓库]wechat-emoji
前端·github
汪子熙15 分钟前
错误剖析:net::ERR_HTTP2_PROTOCOL_ERROR 200 (OK) 的含义与解决之道
前端