Lodash源码阅读-cloneTypedArray

Lodash 源码阅读-cloneTypedArray

概述

cloneTypedArray 是 Lodash 库中的一个内部工具函数,主要用于创建 TypedArray(类型化数组)对象的克隆。TypedArray 是处理二进制数据的专用数组类型,如 Int8Array、Uint8Array、Float32Array 等,这个函数在深度克隆操作中确保了对这类特殊数组的正确处理,支持浅拷贝和深拷贝两种模式。

前置学习

依赖函数

  • cloneArrayBuffer:用于克隆 TypedArray 底层的 ArrayBuffer 对象,在深拷贝模式下使用

技术知识

  • TypedArray:JavaScript 中的类型化数组,包括 Int8Array、Uint8Array、Float32Array 等多种类型
  • ArrayBuffer:类型化数组底层的二进制数据缓冲区
  • 构造函数属性 :JavaScript 对象的 constructor 属性,指向创建该对象的构造函数
  • 浅拷贝与深拷贝:对象复制的两种模式及其在处理引用类型时的区别

源码实现

javascript 复制代码
/**
 * Creates a clone of `typedArray`.
 *
 * @private
 * @param {Object} typedArray The typed array to clone.
 * @param {boolean} [isDeep] Specify a deep clone.
 * @returns {Object} Returns the cloned typed array.
 */
function cloneTypedArray(typedArray, isDeep) {
  var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
  return new typedArray.constructor(
    buffer,
    typedArray.byteOffset,
    typedArray.length
  );
}

实现思路

cloneTypedArray 函数的实现思路清晰直接:

  1. 根据 isDeep 参数决定如何处理 TypedArray 的底层 ArrayBuffer:
    • 如果是深拷贝(isDeep 为 true),则使用 cloneArrayBuffer 函数创建底层 ArrayBuffer 的独立副本
    • 如果是浅拷贝(isDeep 为 false 或未提供),则直接使用原始 TypedArray 的 buffer 引用
  2. 使用原始 TypedArray 的构造函数创建一个新的 TypedArray 实例,传入处理后的 buffer、原始的字节偏移量和长度
  3. 返回新创建的 TypedArray 对象

这种实现方式既可以创建共享底层数据的浅拷贝,也可以创建完全独立的深拷贝,满足不同场景的需求。

源码解析

函数签名

javascript 复制代码
function cloneTypedArray(typedArray, isDeep) {

函数接收两个参数:

  • typedArray:要克隆的类型化数组对象(如 Int8Array、Uint8Array 等)
  • isDeep:可选的布尔值,指定是否进行深拷贝

处理 buffer

javascript 复制代码
var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;

这行代码是函数的核心,它根据 isDeep 参数决定如何处理底层的 ArrayBuffer:

  • 如果 isDeep 为 true,调用 cloneArrayBuffer 函数创建 typedArray.buffer 的深拷贝
  • 如果 isDeep 为 false 或未提供,直接使用原始的 typedArray.buffer 引用

在深拷贝模式下,新创建的 TypedArray 将拥有自己独立的底层数据存储,不会与原始数组共享数据。而在浅拷贝模式下,新旧数组共享同一个底层 ArrayBuffer,对一个数组的修改会影响另一个。

创建新的 TypedArray

javascript 复制代码
return new typedArray.constructor(
  buffer,
  typedArray.byteOffset,
  typedArray.length
);

这行代码创建并返回一个新的 TypedArray 对象:

  1. 通过 typedArray.constructor 获取原始类型化数组的构造函数(如 Int8Array、Float32Array 等)
  2. 使用该构造函数创建一个新的类型化数组实例,传入三个参数:
    • buffer:上一步获取或创建的 ArrayBuffer
    • typedArray.byteOffset:原始类型化数组的字节偏移量
    • typedArray.length:原始类型化数组的长度(元素个数)

使用 constructor 属性而不是硬编码特定的构造函数,使得这个函数可以处理所有类型的 TypedArray,保持了代码的通用性和扩展性。

不同类型的 TypedArray

JavaScript 提供了多种类型化数组,cloneTypedArray 可以处理所有这些类型:

  • Int8Array:8 位有符号整数数组
  • Uint8Array:8 位无符号整数数组
  • Uint8ClampedArray:8 位无符号整数数组(固定范围)
  • Int16Array:16 位有符号整数数组
  • Uint16Array:16 位无符号整数数组
  • Int32Array:32 位有符号整数数组
  • Uint32Array:32 位无符号整数数组
  • Float32Array:32 位浮点数数组
  • Float64Array:64 位浮点数数组

无论哪种类型,cloneTypedArray 都能通过 constructor 属性正确地创建对应类型的克隆。

浅拷贝与深拷贝的区别

javascript 复制代码
// 浅拷贝 - 共享同一个底层 ArrayBuffer
var shallowClone = cloneTypedArray(originalArray, false);

// 深拷贝 - 创建底层 ArrayBuffer 的独立副本
var deepClone = cloneTypedArray(originalArray, true);

// 修改测试
shallowClone[0] = 99; // 也会修改 originalArray[0]
deepClone[0] = 99; // 不会影响 originalArray[0]

浅拷贝和深拷贝的关键区别在于对底层 ArrayBuffer 的处理:

  • 浅拷贝创建的新数组与原始数组共享同一个底层 ArrayBuffer,任何一方的修改都会影响另一方
  • 深拷贝通过复制底层 ArrayBuffer 创建完全独立的新数组,两个数组之间的修改互不影响

总结

cloneTypedArray 是 Lodash 中一个专门用于克隆类型化数组的工具函数,它通过灵活处理底层 ArrayBuffer,实现了对各种类型化数组的浅拷贝和深拷贝。

这个函数的实现体现了几个重要的软件设计原则:

  1. 通用性 :使用 constructor 属性使函数能够处理所有类型的 TypedArray
  2. 灵活性 :通过 isDeep 参数支持浅拷贝和深拷贝两种模式
  3. 组合复用 :利用 cloneArrayBuffer 函数处理底层数据的复制,避免代码重复
  4. 单一职责:函数只关注于类型化数组的克隆,遵循"做好一件事"的原则

在处理二进制数据和数值计算的 JavaScript 应用中,cloneTypedArray 提供了一种简洁而强大的方式来创建类型化数组的副本,为数据处理提供了更多的灵活性和安全性。

相关推荐
Mintopia5 分钟前
在混沌宇宙中捕捉错误的光——Next.js 全栈 Sentry / LogRocket
前端·javascript·next.js
Mintopia7 分钟前
长文本 AIGC:Web 端大篇幅内容生成的技术优化策略
前端·javascript·aigc
VueVirtuoso7 分钟前
SaaS 建站从 0 到 1 教程:Vue 动态域名 + 后端子域名管理 + Nginx 配置
前端·vue.js·nginx
少年阿闯~~14 分钟前
transition(过渡)和animation(动画)——CSS
前端·css·动画·过渡
Async Cipher16 分钟前
CSS 继承 (Inheritance)
前端·css
祈祷苍天赐我java之术23 分钟前
Vue 整体框架全面解析
前端·javascript·vue.js
洛小豆1 小时前
Git 打标签完全指南:从本地创建到远端推送
前端·git·github
世间小小鱼1 小时前
【爬坑指南】亚马逊文件中心 AWS S3 预签名URL 前端直传
前端·云计算·aws
华仔啊1 小时前
前端登录token到底应该存在哪?LocalStorage、SessionStorage还是Cookie?一篇说透!
前端·javascript
BeefyBytes1 小时前
动态组件库建设
前端