一文搞懂:_.cloneDeep(value)

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
数据可视化DataV,5个大屏 1个月
简介: 一文搞懂:_.cloneDeep(value)

119


.cloneDeep(value)


.cloneDeep与clone方法类似,cloneDeep会递归深度克隆一个对象


参数


value (): 需要递归深度克隆的值


返回值


(): 返回深度克隆好的值


例子


var objects = 【{ 'a': 1 }, { 'b': 2 }】;


var deep = .cloneDeep(objects);


console.log(deep【0】 === objects【0】);


// => false


源代码:


baseClone方法和.clone里的是同一个方法


import baseClone from './.internal/baseClone.js'


/ Used to compose bitmasks for cloning. */


const CLONE_DEEP_FLAG = 1


const CLONE_SYMBOLS_FLAG = 4


/


This method is like clone except that it recursively clones value.



@since 1.0.0


@category Lang


@param { } value The value to recursively clone.


@returns { } Returns the deep cloned value.


@see clone


@example



const objects = 【{ 'a': 1 }, { 'b': 2 }】



const deep = cloneDeep(objects)


console.log(deep【0】 === objects【0】)


// => false


/


//与clone方法类似,cloneDeep会递归深度克隆一个对象


function cloneDeep(value) {


return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG)


}


export default cloneDeep


baseClone


import Stack from './Stack.js'


import arrayEach from './arrayEach.js'


import assignValue from './assignValue.js'


import baseAssign from './baseAssign.js'


import baseAssignIn from './baseAssignIn.js'


import cloneBuffer from './cloneBuffer.js'


import copyArray from './copyArray.js'


import cloneArrayBuffer from './cloneArrayBuffer.js'


import cloneDataView from './cloneDataView.js'


import cloneRegExp from './cloneRegExp.js'


import cloneSymbol from './cloneSymbol.js'


import cloneTypedArray from './cloneTypedArray.js'


import copySymbols from './copySymbols.js'


import copySymbolsIn from './copySymbolsIn.js'


import getAllKeys from './getAllKeys.js'


import getAllKeysIn from './getAllKeysIn.js'


import getTag from './getTag.js'


import initCloneObject from './initCloneObject.js'


import isBuffer from '../isBuffer.js'


import isObject from '../isObject.js'


import keys from '../keys.js'


import keysIn from '../keysIn.js'


/** Used to compose bitmasks for cloning. /


//判断克隆的类型,使用二进制掩码标识了深克隆,浅克隆,展平克隆(将继承属性展平)


const CLONE_DEEP_FLAG = 1


const CLONE_FLAT_FLAG = 2


const CLONE_SYMBOLS_FLAG = 4


/ Object#toString result references. */


//对象的toStringTag


const argsTag = '【object Arguments】'


const arrayTag = '【object Array】'


const boolTag = '【object Boolean】'


const dateTag = '【object Date】'


const errorTag = '【object Error】'


const mapTag = '【object Map】'


const numberTag = '【object Number】'


const objectTag = '【object Object】'


const regexpTag = '【object RegExp】'


const setTag = '【object Set】'


const stringTag = '【object String】'


const symbolTag = '【object Symbol】'


const weakMapTag = '【object WeakMap】'


const arrayBufferTag = '【object ArrayBuffer】'


const dataViewTag = '【object DataView】'


const float32Tag = '【object Float32Array】'


const float64Tag = '【object Float64Array】'


const int8Tag = '【object Int8Array】'


const int16Tag = '【object Int16Array】'


const int32Tag = '【object Int32Array】'


const uint8Tag = '【object Uint8Array】'


const uint8ClampedTag = '【object Uint8ClampedArray】'


const uint16Tag = '【object Uint16Array】'


const uint32Tag = '【object Uint32Array】'


/ Used to identify toStringTag values supported by clone. /


//用来确定指定的toStringTag是否支持克隆


const cloneableTags = {}


cloneableTags【argsTag】 = cloneableTags【arrayTag】 =


cloneableTags【arrayBufferTag】 = cloneableTags【dataViewTag】 =


cloneableTags【boolTag】 = cloneableTags【dateTag】 =


cloneableTags【float32Tag】 = cloneableTags【float64Tag】 =


cloneableTags【int8Tag】 = cloneableTags【int16Tag】 =


cloneableTags【int32Tag】 = cloneableTags【mapTag】 =


cloneableTags【numberTag】 = cloneableTags【objectTag】 =


cloneableTags【regexpTag】 = cloneableTags【setTag】 =


cloneableTags【stringTag】 = cloneableTags【symbolTag】 =


cloneableTags【uint8Tag】 = cloneableTags【uint8ClampedTag】 =


cloneableTags【uint16Tag】 = cloneableTags【uint32Tag】 = true


cloneableTags【errorTag】 = cloneableTags【weakMapTag】 = false


/** Used to check objects for own properties. /


//用于检测是否是对象自身的属性


const hasOwnProperty = Object.prototype.hasOwnProperty


/


Initializes an object clone based on its toStringTag.



* Note: This function only supports cloning values with tags of


Boolean, Date, Error, Map, Number, RegExp, Set, or String.



@private


@param {Object} object The object to clone.


@param {string} tag The toStringTag of the object to clone.


@param {boolean} 【isDeep】 Specify a deep clone.


//代码效果参考:http://www.jhylw.com.cn/170622997.html

@returns {Object} Returns the initialized clone.

/


//基于toStringTag初始化对象克隆


//注意:此方法只支持如下类型:Boolean, Date, Error, Map, Number, RegExp, Set, or String.


function initCloneByTag(object, tag, isDeep) {


const Ctor = object.constructor//object的构造函数


switch (tag) {


case


return cloneArrayBuffer(object)


case


case


return new Ctor(+object)


case


return cloneDataView(object, isDeep)


case float32Tag: case float64Tag:


case int8Tag: case int16Tag: case int32Tag:


case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:


//Float32Array Float64Array Int8Array Int16Array Int32Array Uint8Array Uint8ClampedArray Uint16Array Uint32Array


return cloneTypedArray(object, isDeep)


case


return new Ctor


case numberTag:


case stringTag:


//Number String


return new Ctor(object)


case


return cloneRegExp(object)


case


return new Ctor


case


return cloneSymbol(object)


}


}


/


Initializes an array clone.



@private


@param {Array} array The array to clone.


@returns {Array} Returns the initialized clone.


/


//初始化数组的克隆,返回一个初始化的克隆结果,就是和原数组长度一样的但是元素都为空位的数组


function initCloneArray(array) {


const { length } = array//数组的长度


const result = new array.constructor(length)//初始化结果数组


// Add properties assigned by RegExp#exec.


//将正则方法exec()返回的数组的index和input属性克隆到结果数组上


if (length && typeof array【0】 == 'string' && hasOwnProperty.call(array, 'index')) {


result.index = array.index


result.input = array.input


}


return result


}


/*


The base implementation of clone and cloneDeep which tracks


traversed objects.



@private


@param { } value The value to clone.


@param {number} bitmask The bitmask flags.


1 - Deep clone


2 - Flatten inherited properties


4 - Clone symbols


@param {Function} 【customizer】 The function to customize cloning.


@param {string} 【key】 The key of value.


@param {Object} 【object】 The parent object of value.


@param {Object} 【stack】 Tracks traversed objects and their clone counterparts.


@returns { } Returns the cloned value.


/


//clone和cloneDeep的基础实现


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//是否是浅克隆


if (customizer) {//如果传递了自定义克隆方法,用自定义的克隆方法处理


result = object ? customizer(value, key, object, stack) : customizer(value)


}


if (result !== undefined) {//如果自定义克隆处理后能够result有变化,直接返回结果


return result


}


if (!isObject(value)) {//判断要克隆的值是否不是对象是简单值,如果是简单值直接返回


return value


}


const isArr = Array.isArray(value)//判断value是否是array


const tag = getTag(value)//获取value的toStringTag


if (isArr) {//如果value是数组


result = initCloneArray(value)


//初始化克隆数组,返回一个初始化的克隆结果,就是和原数组长度一样的但是元素都为空位的数组


if (!isDeep) {//如果是浅克隆,调用copyArray处理


return copyArray(value, result)


}


} else {//如果value不是数组


const isFunc = typeof value == 'function'//判断value是否是function类型


if (isBuffer(value)) {//如果value是buffer对象


return cloneBuffer(value, isDeep)//使用cloneBuffer克隆buffer对象


}


if (tag == objectTag || tag == argsTag || (isFunc && !object)) {


//如果value的类型是Object arguments 或者是函数并且没有父级对象包裹


result = (isFlat || isFunc) ? {} : initCloneObject(value)


//初始化克隆结果,如果需要展开继承属性或者value是function,那初始化为空对象,否则调用initCloneObject处理


if (!isDeep) {//如果不是深度克隆


//先将普通属性克隆,然后再克隆symbol属性


return isFlat


? copySymbolsIn(value, baseAssignIn(result, value))


: copySymbols(value, baseAssign(result, value))


}


} else {


if (isFunc || !cloneableTags【tag】) {


//其他情况如果是有父级对象的function或者不支持克隆的类型


return object ? value : {}//返回value或者空对象


}


result = initCloneByTag(value, tag, isDeep)


//根据toStringTag来初始化克隆


}


}


// Check for circular references and return its corresponding clone.


//检查循环引用并且返回对应的克隆


stack || (stack = new Stack)//用来存放键值对的数据结构


const stacked = stack.get(value)//获取stack中的value对应的result


if (stacked) {//如果stack中存在直接返回


return stacked


}


stack.set(value, result)//设置value对应result到stack中


if (tag == mapTag) {//如果是map数据类型


value.forEach((subValue, key) => {//循环map复制到result上,递归调用baseClone复制其中的值


result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack))


})


return result


}


if (tag == setTag) {//如果是set数据类型


value.forEach((subValue) => {//循环set复制到result上,递归调用baseClone复制其中的值


result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack))


})


return result


}


if (isTypedArray(value)) {//如果是typedArray直接返回结果


return result


}


const keysFunc = isFull


? (isFlat ? getAllKeysIn : getAllKeys)


: (isFlat ? keysIn : keys)//获取对象key数组的方法根据是否需要展平继承属性使用不同的


const props = isArr ? undefined : keysFunc(value)//获取键组成的数组


arrayEach(props || value, (subValue, key) => {//循环键数组,将值复制


if (props) {


key = subValue


subValue = value【key】


}


// Recursively populate clone (susceptible to call stack limits).


//递归克隆其值是复杂对象的情况,容易受到调用栈大小限制的影响


assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack))


})


return result


}


export default baseClone

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3 )前置知识要求   课程大纲 第一章 了解数据仓库概念 初步了解数据仓库是干什么的 第二章 按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章 数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章 采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章 用户行为数据仓库 严格按照企业的标准开发 第六章 搭建业务数仓理论基础和对表的分类同步 第七章 业务数仓的搭建  业务行为数仓效果图  
相关文章
|
机器学习/深度学习 人工智能 运维
10 分钟搞懂 LLMOps
10 分钟搞懂 LLMOps
795 0
|
人工智能 网络协议 算法
5 分钟搞懂 ECN
5 分钟搞懂 ECN
1605 0
|
5月前
|
C#
一文搞懂:一道关于C#linqwhere的面试题
一文搞懂:一道关于C#linqwhere的面试题
39 0
|
5月前
|
数据可视化 API
一文搞懂:【Havok】
一文搞懂:【Havok】
91 0
|
5月前
|
API
一文搞懂:关于串行接口
一文搞懂:关于串行接口
163 0
|
5月前
一文搞懂:关于“isbuzy”问题
一文搞懂:关于“isbuzy”问题
25 0
|
5月前
|
PHP
一文搞懂:yeild理解
一文搞懂:yeild理解
31 0
|
5月前
|
前端开发 JavaScript
一文搞懂:【Reduc】ReactCounterExample
一文搞懂:【Reduc】ReactCounterExample
37 0
|
5月前
|
机器学习/深度学习 定位技术
一文搞懂:【OpenJ_Bailian
一文搞懂:【OpenJ_Bailian
31 0
|
5月前
一文搞懂:【华为oj】iNOC产品部
一文搞懂:【华为oj】iNOC产品部
27 0