今天我们来读lodash的深拷贝部分代码。
lodash的clone
和cloneDeep
两个方法分别对应浅拷贝
和深拷贝
。两个函数其实都依赖于baseClone
方法,通过传入一个标识
来进行深拷贝或者浅拷贝的区分,我们来简单看一下baseClone
的入参。
/** Used to compose bitmasks for cloning. */
var CLONE_DEEP_FLAG = 1,
CLONE_FLAT_FLAG = 2,
CLONE_SYMBOLS_FLAG = 4;
function clone(value) {
return baseClone(value, CLONE_SYMBOLS_FLAG);
}
function cloneDeep(value) {
return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
}
/**
* @param {*} value The value to clone.
* @param {boolean} 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.
*/
function baseClone(value, bitmask, customizer, key, object, stack) {
// ... 暂时省略内容代码
}
来看下函数baseClone
的入参:
value
代表需要进行拷贝的对象。bitmask
就是深浅拷贝的一个标识,我们可以看到clone
传入的是4,cloneDeep
传入的为1 | 4
为5。customizer
这个参数是为cloneWith
的api进行服务的,是自定义的一个clone
函数,与深拷贝无关,这里我们先忽略。key
对应的为当前拷贝对象的key
,这是后续递归调用拷贝对象值的时候所用到的。object
对应的为value
的所属对象,也是后续递归所用到的。stack
为一个类似于Map数据结构的数组,它以一个二维数组的形式,保存了每次需要进行克隆的值和返回的值,即保存为[value, result]
的形式。具体的作用到函数代码分析中去查看。
baseClone
的深拷贝部分逻辑总体思路很简单,当判断为基本类型的时候,直接返回返回需要拷贝的对象。当为引用类型的时候,根据为数组或者对象,进行一个循环,递归使用baseClone
继续进行拷贝,直到基本的数据类型为止。但这种思路会产生一个问题,当两个对象循环引用的时候,代码会无限循环下去,就如下面这种情况:
var a = {
};
var b = {
result: a }<