_.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. * @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 arrayBufferTag://ArrayBuffer return cloneArrayBuffer(object) case boolTag://Boolean case dateTag://Date return new Ctor(+object) case dataViewTag://DataView 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 mapTag://Map return new Ctor case numberTag: case stringTag: //Number String return new Ctor(object) case regexpTag://RegExp return cloneRegExp(object) case setTag://Set return new Ctor case symbolTag://Symbol 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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架