导航
[深入01] 执行上下文
[深入02] 原型链
[深入03] 继承
[深入04] 事件循环
[深入05] 柯里化 偏函数 函数记忆
[深入06] 隐式转换 和 运算符
[深入07] 浏览器缓存机制(http缓存机制)
[深入08] 前端安全
[深入09] 深浅拷贝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模块化
[深入13] 观察者模式 发布订阅模式 双向数据绑定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手写Promise
[深入20] 手写函数
[部署01] Nginx
[部署02] Docker 部署vue项目
[部署03] gitlab-CI
[源码-webpack01-前置知识] AST抽象语法树
[源码-webpack02-前置知识] Tapable
[源码-webpack03] 手写webpack - compiler简单编译流程
[源码] Redux React-Redux01
[源码] axios
[源码] vuex
[源码-vue01] data响应式 和 初始化渲染
前置知识
堆栈
- stack栈
- 栈区 包含了:变量的标识符 和 变量的值
- 栈区:
- 指的是内存中的栈内存
- 基本类型的数据(值类型数据)保存在栈中
- 比较
- 基本类型数据的比较是(值)得比较
- 基本类型的数据(不可变),不能添加属性和方法
- heap堆
- 堆区
- 引用类型的数据保存在栈和堆中
- 栈区保存:变量标识符 和 指向堆内存中对象的 指针
- 堆区保存:具体的对象数据
- 比较
- 引用类型数据的比较是(引用)的比较
- 引用类型的数据(可变),可以添加属性和方法
- 堆区
数据类型
- 基本数据类型(值类型):number,string,boolean,null,undefined,symbol
- 引用类型的数据:object,array,function等
- 区别:
- 基本类型没有属性和方法,大小固定,保存在栈区
- 引用类型有属性和方法,大小不固定,保存在栈区和堆区,栈中保存指向堆中数据的地址
数据类型的案例
引用类型和原始类型的案例
var a = 1 // 基本类型的数据
var b = {name: 'woow_wu7'} // 引用类型的数据
var aa = a // a 和 aa 是不同的数据
var bb = b // b 和 bb 指向堆中的同一份数据,修改堆中数据,b和bb的指向没变,则引用的值也会跟着改变
a = 2
b.name = 'wang'
console.log(a, aa, 'a和aa是不同的数据') // 改变后不等
console.log(b.name, bb.name, 'b和bb两个变量中的指针 => 都同时指向了同一个堆内存中的数据') // 改变后相等
console.log(b === bb) // true,说明两个变量指向了同一个堆内存
Map数据结构
- Object对象的key只能是字符串
字符串-值
对应
- Map数据结构的key可以是任意类型
值-值
对应
- Map类似于对象,也是key,value的键值对的集合
- Map是一种更完善的hash结构实现,如果你需要键值对的数据结构,Map比Object更合适
Map.prototype.set(key, value) // key可以是任意类型
Map.prototype.get(key)
Map.prototype.has(key) // 返回布尔值
Map.prototype.delete(key) // 删除某个键,但返回布尔值,表示是否删除成功
Map.prototype.clear() // 清除所有成员,没有返回值
Map.prototype.keys() values() entries() forEach()
- Map构造函数可以接受数组为参数,成员必须是一个个表示键值对的数组
- Map能保证对象key的唯一性
const mapArrKey = [1,2];
const mapKeyAddress = ['chongqign']
const mapInstance = new Map([
['name', 'woow_wu'],
[[1,2], 20],
[mapArrKey, 20],
[{age: 20}, {age: 20}],
])
console.log(mapInstance, 'mapInstance')
console.log(mapInstance.size, 'size') // 4
console.log(mapInstance.get(mapArrKey), 'Map.prototype.get(key) => key是一个数组')
console.log(mapInstance.get([1,2]), 'Map.prototype.get(key)') // undefined 必须是同一个数组
mapInstance.set(mapKeyAddress, '地址')
console.log(mapInstance.get(mapKeyAddress))
console.log(mapInstance.has(mapKeyAddress), 'Map.prototype.has(key) => key是否存在,布尔值') // true
console.log(mapInstance.delete(mapKeyAddress), 'Map.prototype.delete(key) => 删除键,返回布尔值,表示是否删除成功') // true
console.log(mapInstance.get(mapKeyAddress)) // undefined
console.log(mapInstance.clear(), 'Map.prototype.clear() => 删除所有键,没有返回值')
console.log(mapInstance)
Reflect
- 操作对象的api
- reflect:反映,反射的意思
Reflect.get(target, name, receiver)
- 获取target对象的name属性,如果没有该属性返回undefined
- 如果name属性部署了getter函数,getter函数中的this指向receiver参数对象
- 如果target参数不是对象,Reflect.get()会报错
Reflect.set(target, name, value, receiver)
- 设置target对象的name属性为value
- 如果name属性部署了settter函数,setter函数中的this指向receiver参数对象
Reflect.deleteProperty(obj, name)
- 删除obj的name属性
- 相当于: delete obj.name
Reflect.constructor(target, args)
- 执行构造函数target,传入target构造函数的参数是args
- 如果target不是函数,就会报错
Reflect.getPrototypeOf(obj)
- 相等于:Object.getPrototypeOf(obj)
Reflect.setProrotypeOf(obj, prototypeObj)
Reflect.apply(func, thisArg, args)
- 等于:Function.prototype.apply.call(func, thisArg, arges)
- Reflect.ownKeys(target)
返回对象参数的所有属性,注意:包括Symbol类型的属性
等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和
- 包括symbol类型的属性!!!
2021/10/04 更新如下
Object.keys() 和 Object.getOwnPropertyNames() 的区别 ?
- 相同点
- 两者都用来 ( 遍历对象的属性 )
- 都返回一个 ( 数组 ),包含对象所有 (
自身属性名 - 注意不包括继承的属性
)
- 不同点
- 两者对 ( 不可枚举 ) 属性的处理不同
- Object.keys() ---------------------- 只返回 ( 可枚举 ) 的属性
- Object.getOwnPropertyNames() --- 返回 ( 可枚举 + 不可枚举 ) 属性
- 总结
- 都返回自身属性名组成的数组,但是对不可枚举属性的处理不同
- 范围:Object.getOwnPropertyNames() > Object.keys()
运算符的结合性
- 一元运算符,三元运算符,赋值运算符是右结合,其他的都是左结合
三元运算符是右结合:即从右向左算,先算右边的三元表达式,再算左边的三元表达式
三元运算符右结合
let name = null
1 === true ? name = 'wang' : 1 < 0 ? name = 'zhang' : name = 'woow_wu7';
//相当于:1 === true ? name = 'wang' : (1 < 0 ? name = 'zhang' : name = 'woow_wu7')
console.log(name, 'name')
// 'woow_wu7'
// 1 === true // false,类型不一样都是false
typeof返回值
- typeof可以用来判断基本数据类型,返回值是字符串
- typeof不能区分对象类型的数据:如对象还是数组
- typeof 的返回值一共有7种类型
typeof
- 返回值有(8种):number,string,boolean,undefined,symbol,bigInt,object,function
- 基础数据类型(6种):number,string,boolean,undefined,symbol,null
typeof NaN ---------------------- 'number'
typeof Symbol() ----------------- 'symbol'
typeof function(){} ------------- 'function'
typeof [] ---------------------- 'object'
typeof {} ---------------------- 'object'
typeof null --------------------- 'object'
typeof BigInt(4) ---------------- 'bigint'
浅拷贝和深拷贝的区别
- 浅拷贝是只进行一层拷贝,深拷贝是拷贝所有层级,直到属性对应的值是原始数据为止
- 浅拷贝
- 创建一个新对象(开创一个新的堆空间),该新对象有着原始对象属性值的精确拷贝
- 属性值是基本类型,拷贝的就是基本类型的值(
即拷贝的是值,互不干扰
) - 属性值是引用类型,拷贝的就是指向堆内存的指针(
即拷贝的是指针,相互干扰
)
- 深拷贝
- 在堆内存中创建一个新空间,把对象完成的拷贝到新空间中,相互独立,互不干扰
浅拷贝和赋值的区别
之所以不易区分浅拷贝和赋值,是因为拷贝后一般都伴随者赋值
- 赋值:两个变量对象的指针,指向同一个堆内存中的对象数据,不会开创新的堆空间
- 浅拷贝:开创一个新的堆内存空间(即创建一个新对象),新对象是对原始对象的一个精确拷贝,属性是基本类型的值拷贝的就是基本类型的值,如果属性是引用类型的值,拷贝的就是堆内存的指针
-
一句话总结: (1)赋值不会开创新的堆内存空间,而浅拷贝会开创新的堆内存空间;
(2)赋值:改变对象属性相互影响;
(3)浅拷贝:改变属性值是原始类型时,互不干扰。改变的属性值是引用类型时,相互影响
赋值和浅拷贝的区别实例
赋值和浅拷贝的区别
var a = {
name: 'woow_wu',
score: {
ch: 90,
en: 80
}
};
var b = a
var c = {...a}
console.log(a===b, '赋值 => 不会开创新的堆空间,修改相互影响') // true,说明是同一份堆数据
console.log(a===c, '浅拷贝 => 会开创新的堆空间,修改原始值属性互不干扰,修改引用值属性,相互影响') // false,不同堆数据
a.name = 'wang'
console.log(b, 'b') // 相互影响
console.log(c, 'c => 浅拷贝,修改属性值为基本类型 => 互不干扰') // 互不干扰
a.score.en = 100
console.log(c, 'c => 浅拷贝,修改属性值为引用类型 => 相互影响') // 相互影响
浅拷贝
对象的浅拷贝
- Object.assign()
- {...} 展开运算符
数组浅拷贝
- Array.prototype.slice()
// 不传参
- Array.prototype.concat()
// 不传参
- [...] 展开运算符
const arr = [1, 2, 3]
---
1. slice
- slice(start, end)
- 截取目标数组的一部分,----------------------------------- ( 返回一个新数组,不改变原数组 )
- start起始位置,从0开始,可以取到
- end终止位置,注意取不到end // arr.slice(0, 2) // [1, 2]
- 下面三种写法等价
- arr.slice()
- arr.slice(0)
- arr.slice(0, 3) 三者的结果一样
2. concat
- concat
- 用于多个数组的合并,它将新数组的成员,添加在原属数组的尾部,---- ( 返回一个新数组,不改变原数组 )
- 参数
- concat的参数除了是 ( 数组 ) 还可以是 ( 其他任意类型的值 )
3. 数组的浅拷贝
- arr.concat() // 不加参数
- arr.slice() // 不加参数
- [...arr]
2021/10/01 复习优化 - 浅拷贝
- 对象
{...obj}
Object.assign(obj)
- 数组
Array.prototype.slice.call(arr)
arr.slice()
arr.slice(0) // 从0开始截取到最后一个元素,即截取整个数组
- arr.concat()
- arr.concat([])
- Array.prototype.concat.call(arr)
- Array.prototype.concat.call(arr,[])
- Array.prototype.concat.apply(arr,[])
- 注意:
- 这里call和apply都可以传入空数组
- 只是:call只能一个一个的传入值,这个值可以是任意类型,包括数组
- 但是:apply只能是一个数组
- 注意:
[...arr]
深拷贝
方法一 JSON.parse(JSON.stringify())
- 缺点:
- 只能深拷贝对象和数组,但不能拷贝函数,循环引用,原型链上的属性和方法(Date, RegExp, Error等)
const objComplex = {
name: 'woow_wu7',
address: {
city: 'chongqing',
district: 'yubei',
town: 'jiazhou',
detail: ['chongqing', 'yubei', 'jiazhou']
},
arr: [1,2, {l:20, r: 30}],
fn: function(){}, // Function
date: new Date(), // Date
err: new Error(), // Error
reg: new RegExp(), // RegExp
number: 1,
string: '',
boolean: true,
null: null,
undefined: undefined,
symbol: Symbol('symbol'), // Symbol
}
const copy = JSON.parse(JSON.stringify(objComplex))
console.log(objComplex, 'objComplex')
console.log(copy, 'copy')
如下图:
JSON.parse(JSON.stringify()) 不能拷贝function,Date,Error,RegExp,等对象
方法二
基础版 - for...in循环递归(1)
- 要求:可以拷贝对象和数组
- 未解决:
- 循环引用
- Symbol()类型key的属性对应值的拷贝
- 其他对象的复制如 Date,Error,Regexp,Symbol数据类型等
const objComplex = {
name: 'woow_wu7',
address: {
city: 'chongqing',
district: 'yubei',
town: 'jiazhou',
detail: ['chongqing', 'yubei', 'jiazhou']
},
score: [100, 200]
}
function deepClone(parameter) {
const parameterType = Object.prototype.toString.call(parameter).slice(8, -1)
// 获取类型字符串
// Array.prototype.slice(8, -1) 从下标为8的字符开始截取,直到倒数第2个值
// 因为第一个参数位置可以取到,第二个参数位置取不到
const cloneObj = null
// 参数是数组,赋值[]
// 参数是对象,赋值{}
// 其他类型:直接返回
if (parameterType === 'Array') {
cloneObj = []
}
else if (parameterType === 'Object') {
cloneObj = {}
}
else {
return parameter
}
for(let key in parameter) {
// for...in
// 1. 循环用来遍历对象 ( 所有可遍历的属性 ),会 ( 跳过不可遍历的属性 )
// 2. 不仅可以遍历 ( 自身属性 ),还可以遍历 ( 继承的属性 )
// 3. 所以一般情况下,( for...in都要结合hasOwnProperty来遍历自身的属性 )
if (parameter.hasOwnProperty(key)) {
// 是否是自身属性
if (typeof parameter[key] === 'object') {
// 对象或数组,继续判断
// 这里使用typeof没有去区是分数组或对象,因为会在deepClone中去做判断
cloneObj[key] = deepClone(parameter[key])
} else {
// typeof不是objet
// 则有可能是:number string boolean undefined symbol function
// 这里没有考虑 function 的拷贝
cloneObj[key] = parameter[key]
}
}
}
return cloneObj
}
const res = deepClone(objComplex)
console.log(res, 'res')
----------
更精简的写法
const obj = {
name: 'woow_wu7',
address: {
city: 'chongqing',
districe: 'yubei',
town: 'jiazhou',
detail: ['chongqign', 'yubei', 'jiazhou']
},
arr: [1,2]
}
function deepClone(parameter) {
if (typeof parameter === 'object') {
// 这里只考虑 对象和数组
// typeof返回值是字符串,有7种
// number string boolean undefined symbol function object
const objClone = Array.isArray(parameter) ? [] : {}
for (let key in parameter) {
if (parameter.hasOwnProperty(key)) {
objClone[key] = deepClone(parameter[key])
// 不管是对象类型还是基本数据类型,都去调用deepClone(parameter[key])
// 在deepClone()函数中会去判断对象类型是数组还是对象,基本数据类型直接返回并赋值给objClone[key]
}
}
return objClone
}
else {
// 不是数组和对象直接返回形参
// 注意形参是新声明的变量
return parameter
}
}
const res = deepClone(obj)
console.log(obj)
console.log(res)
2021/10/03 复习优化 - 基本版
// 知识点
// 1
// Object.entries(obj)
// - 返回一个对象的 ( 自身的,不含继承属性 ),( 可遍历的 - enumerable ) 属性组成的 ( 键值对数组 )
// - 因为返回一个数组,所以可以接着用 for of 来遍历
// 2
// 数据类型:7种
// - 基本数据类型:number string boolean null undefined symbol
// - 引用数据类型:object - Object Array Function Regexp Error Date XMLHttpRequest ...
// 3
// 递归
// - 边界条件
// - 递归前进段
// - 递归返回段
function deepClone(obj) {
// isType 判断参数具体类型
const isType = (obj) =>
Object.prototype.toString
.call(obj)
.replace(/^\[object (.+)\]$/, "$1")
.toLowerCase();
const type = isType(obj);
// 1. 数组和对象类型
if (type === "object" || type === "array") {
const res = type === "array" ? [] : {};
for (let [key, value] of Object.entries(obj)) {
if (typeof value === "object" && value !== null) {
res[key] = deepClone(value); // 属性是对象或数组,递归
} else {
res[key] = value; // 其他类型直接复制
}
}
return res;
}
// 2. 参数不是对象和数组,直接返回原参数 - 这里表示number,string,boolean,undefined,symbol,null,function都直接返回
else {
return obj;
}
}
const deepObj = deepClone(obj);
obj.num = 2; // 测试修改原对象属性
obj.arr = [1, 2, 3]; // 测试修改原对象属性
console.log(`原对象`, obj);
console.log(`新对象`, deepObj);
Map 解决循环引用 - for...in循环递归(2)
- 要求: 可以拷贝对象和数组,并解决循环引用问题
(1) 什么是循环引用?
const obj = {name: 'wang'}
obj.circle = obj
// obj新增circle属性,值是obj对象本身
// 这样的情况,像上面的代码例子中,for..in循环中deepClone(parameter[key])会不断重复执行
// 最终造成内存溢出
----------
(2) 如何解决循环引用?
1. 检查map实例中是否有克隆过的对象
2. 如果存在,直接返回
3. 如果不存在,就赋值键值对,key是传入的对象,value是克隆的对象
var objComplex = {
address: {
city: 'chongqing',
town: 'jiazhou',
},
score: [100, 200],
}
objComplex.circular = objComplex
function deepClone(objComplex, mapx = new Map()) { // 默认值,是一个空的map实例
if (typeof objComplex !== 'object') {
// 不是对象和数组直接返回
return objComplex
}
const objClone = Array.isArray(objComplex) ? [] : {}
if (mapx.get(objComplex)) { // 这里也可以用mapx.has()
// 存在被克隆的对象,直接返回
return mapx.get(objComplex)
}
// 不存在,就添加键值对,将被克隆对象作为key,克隆的对象作为value
mapx.set(objComplex, objClone)
for(let key in objComplex) {
objClone[key] = deepClone(objComplex[key], mapx)
// 注意:mapx要传入做判断
// 不管objComplex[key]是什么类型,都调用deepClone(),因为在deepClone()中会判断
}
return objClone
}
const res = deepClone(objComplex) // 这样就不会内存溢出了
console.log(res, 'res')
Reflect 解决Symbol数据类型复制 - Reflect.ownKeys()循环递归(3)
- 要求: 可以拷贝对象和数组,并解决循环引用问题,并解决Symbol数据类型
- 解决 Symbol 数据类型
- Symbol不能用 new 去调用,参数可以是数组
- Reflect
Reflect.ownKeys(obj)
返回参数对象
的所有自身属性
,包括symbol
数据类型的属性- 参数如果不是obj,则会抛出typeError
- 缺点:Reflect不能取到原型链上的属性和方法
- 以下是2021/10/04更新
- 是 Reflect.ownKeys = Object.getOwnPropertyNames() + Object.getOwnPropertySymbols() 的和
- 注意对比下面三个方法
- Object.keys() //
自身属性 + 可枚举属性
- Object.getOwnPropertyNames() //
自身属性 + 可枚举属性 + 不可枚举属性 - Symbol
- Reflect.ownKeys() //
自身属性 + 可枚举属性 + 不可枚举属性 + Symbol()属性
- Object.keys() //
用 Reflect 解决 Symbol类型数据的复制
var objComplex = {
address: {
city: 'chongqing',
town: 'jiazhou',
},
score: [100, 200],
}
objComplex.circular = objComplex
objComplex[Symbol()] = 'symbol'
function deepClone(objComplex, mapx = new Map()) {
if (typeof objComplex !== 'object') {
return objComplex
}
const objClone = Array.isArray(objComplex) ? [] : {}
if (mapx.get(objComplex)) {
return mapx.get(objComplex)
}
mapx.set(objComplex, objClone)
// for(let key in objComplex) {
// objClone[key] = deepClone(objComplex[key], mapx)
// }
Reflect.ownKeys(Array.isArray(objComplex) ? [...objComplex] : { ...objComplex }).forEach(key => {
// Reflect.ownKeys(obj)返回对象参数的所有属性,包括symbol类型的属性
objClone[key] = deepClone(objComplex[key], mapx)
})
return objClone
}
const res = deepClone(objComplex)
console.log(res, 'res')
2021/06/20 优化
- 上面的ownKeys参数中是不需要判断是不是数组的,因为ownKeys可以遍历数组和对象
<script>
// deep clone
const obj = {
name: "woow_wu7",
address: {
city: "chongqing",
districe: "yubei",
town: "jiazhou",
detail: ["chongqign", "yubei", "jiazhou"],
},
arr: [1, 2],
[Symbol("unique")]: "unique",
};
obj.circle = obj;
const deepClone = (param, map = new Map()) => {
let typeParams = Object.prototype.toString.call(param);
if (typeof param !== "object" && typeof param !== "function") {
return param;
}
if (map.get(param)) {
return map.get(param);
}
let resObj = Array.isArray(param) ? [] : {};
map.set(param, resObj);
// for (let key in param) {
// resObj[key] = deepClone(param[key], map);
// }
Reflect.ownKeys(param).forEach((key) => { // ownKeys参数中,不用做判断是不是数组了
resObj[key] = deepClone(param[key], map);
});
return resObj;
};
const newObj = deepClone(obj);
newObj.name = "222";
console.log(`newObj`, newObj);
console.log(`obj`, obj);
</script>
结构化克隆算法解决其他对象的拷贝 (4)
- 要求: 可以拷贝对象和数组,并解决循环引用问题(Map缓存),并解决Symbol数据类型(Reflect.ownKeys()),解决其他对象的拷贝(结构化克隆),构造函数生成实例的原型对象的拷贝
- 比如:Date,Regexp,构造函数生成的实例的原型对象的属性拷贝
-
缺点:不能处理Error,不能处理Function,不能处理DOM节点
function Message() {
this.sex = 'man'
}
Message.prototype.age = 1000
var objComplex = {
address: {
city: 'chongqing',
town: 'jiazhou',
},
score: [100, 200],
[Symbol()]: 'symbol',
date: new Date(),
reg: new RegExp(),
fn: function () { },
err: new Error(),
message: new Message()
}
objComplex.circle = objComplex
function deepClone(objComplex, mapx = new Map()) {
if (typeof objComplex !== 'object') {
return objComplex
}
let objClone = Array.isArray(objComplex) ? [] : {}
if (mapx.get(objComplex)) {
return mapx.get(objComplex)
}
mapx.set(objComplex, objClone)
// for(let key in objComplex) {
// objClone[key] = deepClone(objComplex[key], mapx)
// }
// Reflect.ownKeys(Array.isArray(parameter) ? [...parameter] : { ...parameter }).forEach(key => {
// objClone[key] = deepClone(parameter[key], mapx)
// })
switch (objComplex.constructor) { // 传入的参数对象的构造函数
case Date:
case RegExp:
case Message: // 自定义的构造函数
objClone = new objComplex.constructor(objComplex)
break
// 如果是Date,RegExp,Message构造函数的请求
// 就分别用这些构造函数生成实例,然后再赋值给拷贝对象
default:
Reflect.ownKeys(Array.isArray(objComplex) ? [...objComplex] : {...objComplex}).forEach(key => {
objClone[key] = deepClone(objComplex[key], mapx)
})
}
return objClone
}
const res = deepClone(objComplex)
console.log(res, 'res')
console.log(res.message.age, '克隆的对象')
console.log(objComplex.message.age, '原对象')
2021/07/17复习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
// deepClone
// 1. Map 解决循环引用 => 缓存
// 2. Reflect 解决Symbol()数据类型 => Reflect.ownKeys()
// 3. 结构化克隆解决特殊对象的拷贝 => Date RegExp
// - 虽然结构化克隆解决了 ( Date ) ( RegExp ) 对象的拷贝问题
// - 但是结构化克隆仍然没有解决 ( Error ) ( function ) ( DOM节点 ) 的拷贝问题
const obj = {
num: 1,
str: "str",
boo: true,
und: undefined,
[Symbol()]: Symbol(),
arr: [1, 2, 3],
obj: { name: "woow_wu7" },
date: new Date(),
regexp: new RegExp(),
};
obj.circle = obj;
const deepClone = (params, map = new Map()) => {
if (typeof params !== "object") {
return params;
}
let resObj = Array.isArray(params) ? [] : {};
if (map.get(params)) {
return map.get(params);
}
map.set(params, resObj);
// for (let key in params) {
// if (params.hasOwnProperty(key)) {
// resObj[key] = deepClone(params[key], map);
// }
// }
// Reflect.ownKeys(params).forEach(key => {
// resObj[key] = deepClone(params[key], map)
// })
switch (params.constructor) {
case Date:
case RegExp:
resObj = new params.constructor(params);
break;
default:
Reflect.ownKeys(params).forEach((key) => {
if (typof deepClone(params[key]) === 'object') {
resObj[key] = deepClone(params[key], map);
} else {
resObj[key] = deepClone(params[key])
}
});
break;
}
return resObj;
};
const res = deepClone(obj);
console.log(`res`, res);
console.log(`obj`, obj);
</script>
</body>
</html>
基本:juejin.im/post/684490…
深入:juejin.im/post/684490…
知乎(lodash deepClone源码分析):zhuanlan.zhihu.com/p/41699218
stack,heap:segmentfault.com/a/119000000…
juejin.im/post/684490…
我的简书 www.jianshu.com/p/a2306eba0…