lodash之cloneDeep()源码阅读笔记

这篇具有很好参考价值的文章主要介绍了lodash之cloneDeep()源码阅读笔记。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

lodash之cloneDeep()源码阅读笔记

基本上都在写业务代码,没有机会写库,还是想了解一下lodash的库源码是怎么样的,平时用的最多的就是cloneDeep()方法了,终于有空详细看看其中的源码。

本文基于lodash@5.0.0版本的源码进行阅读。

/cloneDeep.js

cloneDeep入口函数
import baseClone from './.internal/baseClone.js';

const CLONE_DEEP_FLAG = 1
const CLONE_SYMBOLS_FLAG = 4
function cloneDeep(value) {
  return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG)
}

export default cloneDeep

调用了一个内部的方法,传入的参数中有一个CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG,查了一下mdn文档操作符|,是一个按位或的语法。

const a = 1; // 00000000000000000000000000000001
const b = 4; // 00000000000000000000000000000100

console.log(a | b); // 00000000000000000000000000000101
// Expected output: 5

给我看懵了,注释是说用于合成用于克隆的位掩码,也不知道为啥这样传,继续看baseClone的代码。

/.internal/baseClone.js

lodash中很多代码都抽象出来了,先找到baseClone方法

位掩码传参
const CLONE_DEEP_FLAG = 1
const CLONE_FLAT_FLAG = 2
const CLONE_SYMBOLS_FLAG = 4
/**
* @param {number} bitmask 位掩码标志.
*  1 - 深拷贝
*  2 - 扁平化继承属性
*  4 - 克隆 symbols
*/
function baseClone(value, bitmask, customizer, key, object, stack) {
  let result
  const isDeep = bitmask & CLONE_DEEP_FLAG
  const isFlat = bitmask & CLONE_FLAT_FLAG
  const isFull = bitmask & CLONE_SYMBOLS_FLAG
  // ...
}

这一部分结合bitmask参数的注释,算是看明白为啥用按位或这样的方式进行传参了。这里想到linux的权限的方式,就可以只传一个参数,实际上是可以判断三个boolean类型的参数,还能加更多,秒啊。

非对象的判断,原始数据类型直接返回
// baseClone.js
if (!isObject(value)) {
    return value
}
// /isObject.js
function isObject(value) {
  const type = typeof value
  return value != null && (type === 'object' || type === 'function')
}

export default isObject

这里判断了传入被clone的值不是一个对象或函数,则直接返回,对于原始数据类型的话,是可以直接clone的。

判断是正则RegExp#exec方法执行结果

接下来采用const isArr = Array.isArray(value)判断了值是否是数组,然后初始化了一个同等长度的数组,其中又有一个看不懂的判断

const hasOwnProperty = Object.prototype.hasOwnProperty
if (length && typeof array[0] === 'string' && hasOwnProperty.call(array, 'index')) {
    result.index = array.index
    result.input = array.input
  }

Object.prototype.hasOwnProperty.call(array, ‘index’)是可以判断array中是否有index属性,这数组中有index属性,仔细看注释,添加由RegExp#exec指定的属性,想到这个可能是RegExp中的exec方法执行的结果,RegExp.prototype.exec(),发现果然是有元素0是字符串,并且含有index和input两个元素。

// 例如
RegExp('foo*', 'g').exec('table football, foosball')
// 控制台结果
// 0: "foo"
// groups: undefined
// index: 6
// input: "table football, foosball"
// length: 1
// [[Prototype]]: Array(0)
clone buffer

对于深拷贝的buffer,平时的业务场景,基本上不用到buffer,发现处理是使用了buffer的一个ArrayBuffer.prototype.slice()方法,返回一个新的 ArrayBuffer。

initCloneObject 初始化克隆对象

对于扁平的和函数,是直接使用{},对于其他的一些从原型链继承的自定义对象,使用了Object.create(Object.getPrototypeOf(object))来初始化对象。

Boolean和Date使用构造器创建对象
function initCloneByTag(object, tag, isDeep) {
    const Ctor = object.constructor
    switch (tag) {
        // ...
        case boolTag:
        case dateTag:
            return new Ctor(+object)
          // ...
        case mapTag:
            return new Ctor
        case setTag:
            return new Ctor
    }
}

对于Boolean对象和Date对象直接采用了Object.prototype.contructor取对象的构造器来进行对象创建,其中用到了一个前+的计算,把false、true,以及Date对象转成了数字。

set和map分别实例化一个新的对象

Stack对象

看/.internal/Stack.js中实现了栈数据类型,包含data和size属性,以及基础的清空、删除、查找是否存在、新增、根据索引获取值,实现了一个最大长度为200的栈。

lodash倒是没有实现判断空的方法,而是直接在ListCache对象的delete方法中判断了data的长度是否为零,为零的话栈中是没有元素可以删除的,返回了false。

栈是先入后出的特殊链表,之前学数据结构的时候已经实现过js的stack结构。

Set和Map类型的数据,遍历递归并压入栈
stack || (stack = new Stack)
  const stacked = stack.get(value)
  if (stacked) {
    return stacked
  }
  stack.set(value, result)

  if (tag == mapTag) {
    value.forEach((subValue, key) => {
      result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack))
    })
    return result
  }

  if (tag == setTag) {
    value.forEach((subValue) => {
      result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack))
    })
    return result
  }

这里对于Map和Set中的下一级对象,采用了递归调用的方式进行赋值操作,并且把实例化的栈的信息传递进去,看注释采用Stack是检查循环引用并返回其对应的克隆。

总结

整体的实现思路大概是:

首先判断要复制的对象是否为原始类型,如果是原始类型则直接返回该值。如果是引用类型(如对象或数组),则进行深度复制。

创建一个新的空对象或数组作为目标对象。

遍历要复制的对象的属性或元素,对每一个属性或元素进行递归复制,直到所有嵌套的对象或数组都被复制为止。

使用递归复制的方式,将源对象或数组的属性或元素复制到目标对象或数组中。如果属性或元素本身是一个引用类型,则递归调用 baseClone 进行深度复制。

返回复制完成的目标对象或数组。文章来源地址https://www.toymoban.com/news/detail-648425.html

到了这里,关于lodash之cloneDeep()源码阅读笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端进化笔记-JavaScript(三)

    人类在白色的底色上描绘图画,地球在黑色的底色上创造生命。 JavaScript的变量可以说是独树一帜。只需要一个(或两个等)(const,let)就可以创建变量,创建时不考虑变量的类型,这是其他语言少有的强大功能。当然强大的功能总是伴随着问题。 原始值:Undefined,

    2024年02月08日
    浏览(82)
  • Web前端 Javascript笔记3

     内存中的生命周期         1、内存分配         2、内存使用(读写)         3、内存回收,使用完毕之后,垃圾回收器完成         内存泄漏:该回收的,由于某些未知因素,未释放,叫做内存泄漏 栈:数据存在其中会自动释放 堆:对象,根据程序员的操作来决定释

    2024年04月15日
    浏览(47)
  • 【前端学习笔记2】javaScript基础

    是一种运行在客户端(服务器的编程语言) javacript分为行内JavaScript,内部JavaScript,外部JavaScript 内部JavaScript 直接写在html中body里面 alert(“hello,world”) 我们将script放在html文件的地步附近的原因是浏览器会按照代码在文件中的顺序加载html 如果先加载的JavaScript期望修改其

    2024年01月22日
    浏览(37)
  • web前端javascript笔记——(13)事件(1)

    鼠标/键盘属性 altKey               返回当事件被触发时,“ALT”是否被按下。 button               返回当事件被触发时,哪个鼠标按钮被点击 clientX               返回当事件被触发时,鼠标指针的水平坐标。 clientY               返回当事件被触

    2024年01月25日
    浏览(52)
  • web前端javaScript笔记——(11)DOM

    属性                                     此事件发生在何时 onabort 图像的加载被中断。 onblur                                   元素失去焦点。 anchange                                 域的内容被改变 onclick  当用户点击某

    2024年01月19日
    浏览(60)
  • 前端学习笔记:JavaScript基础语法(ECMAScript)

    此博客参考b站:【黑马程序员前端JavaScript入门到精通全套视频教程,javascript核心进阶ES6语法、API、js高级等基础知识和实战教程】https://www.bilibili.com/video/BV1Y84y1L7Nn?p=76vd_source=06e5549bf018e111f4275c259292d0da 这份笔记适用于已经学过一门编程语言(最好是C语言)的同学,如果你没有

    2024年02月16日
    浏览(47)
  • 前端学习心得笔记之三(JavaScript篇)

    JavaScript一种运行在客户端(浏览器)上的解释性弱语言,是前端的重中之重,在计算机刚刚兴起的那个时代,这个由十天仓促编成的语言发展到现在也是令人吹嘘。 文件引用 在一个单独的js文件中也可以编写JavaScript代码,然后在HTML文件使用script标签进行引用以下为演示 m

    2024年04月23日
    浏览(49)
  • 前端安全——最新:lodash原型漏洞从发现到修复全过程

    人生的精彩就在于你永远不知道惊喜和意外谁先来,又是一个平平无奇的早晨,我收到了一份意外的惊喜——前端某项目出现lodash依赖原型污染漏洞。咋一听,很新奇。再仔细一看,呕吼,更加好奇了~然后就是了解和修补漏洞之旅。 最后的最后,却发现其实这个漏洞修复起

    2024年04月10日
    浏览(61)
  • 【JavaEE初阶】前端第四节.JavaScript入门学习笔记

    作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:Java测试开发 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!! 前言 一、前置知识  1、JS 和 HTML 和 CSS 之间的关系 1.2 JS 的书写形式 1.2.1 内嵌式 1.2.2 行内式  1.2.3 外部式 1.2.4 扩展 1.2

    2024年02月08日
    浏览(51)
  • UE5.2 LyraDemo源码阅读笔记(五)输入系统

    Lyra里使用了增强输入系统,首先知道增强输入系统里的三个类型配置。 一、Input Actions (IA): 输入操作带来的变量,与玩家的输入组件绑定,回调里驱动玩家行为。 二、InputMappingContext(IMC): 表示一套按键输入配置,让按键与IA绑定,从而使用按键携带的变量驱动IA生效。

    2024年02月12日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包