😄本文首发于: lodash-source-learning/
一、概要
工具库 lodash 在开发过程中为我们封装了丰富便捷的js函数,实现一些常用的功能,在使用过程中就会对lodash的内部实现原理感到好奇。
本次文章的主要内容分析阅读了lodash中深拷贝 _.cloneDeep()
的实现。
二、深拷贝和浅拷贝之间的区别
浅拷贝:对于引用类型的数据来说,赋值运算只是更改了引用的指针,但是指针指向的地址还是同一个,所以对应的变动会影响双方。
深拷贝:递归拷贝一个对象中的字对象,完成后两个对象不互相影响。
三、什么样的数据在深拷贝适用范围
包括但不限于:
- Date对象
- Object
- Array
- TypedArray
- Map
- Set
- ArrayBuffer
- RegExp
四、lodash如何实现深拷贝
1、初始化
const CLONE_DEEP_FLAG = 1
const CLONE_SYMBOLS_FLAG = 4
function deepClone(value) {
return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG)
}
cloneDeep
的主体函数baseClone
:
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
}
以上入口代码看起来很简洁:定义两个位掩码常量,通过位运算控制参数类型,达到控制参数权限的基本实现:
1 | 4 & 1 => 1
1 | 4 & 2 => 0
1 | 4 & 4 => 4
由上面的位元算可得知,在当前深拷贝模式下,isDeep
和 isFull
为true
,这两个变量在下面的代码中起到很大的判断作用。
关于javascript中位运算可以参考MDN:Bitwise_Operators。
2、标记值的类型
const tag = getTag(value)
const toString = Object.prototype.toString
function getTag(value) {
if (value == null) {
return value === undefined ? '[object Undefined]' : '[object Null]'
}
return toString.call(value)
}
以上实现通过调用Object
的原型toString()
方法,区别不同value
对应的具体类型:
var toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
//JavaScript版本1.8.5 及以上
toString.call(undefined); // [object Undefined]
toString.call(null