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