深拷贝的五种实现方式
一、数据类型
基本数据类型(String,Number,Boolean,null,Undefined):直接存储在栈(stack)中的数据
(object):存储时会在栈内存存储引用(堆内存中存值的地址),堆内存存储真正的值,栈内存中的引用指向堆内存的值。
二、浅拷贝与深拷贝
浅拷贝:当把一个对象赋值给一个新的变量时,复制的其实是该对象的在栈中的引用地址(指向某个对象的指针),而不是对象值本身,新旧对象指向堆内存中同一片地址空间,共享同一块堆内存,无论哪个对象发生变化,其实都是改变的内存空间的内容,因此,两个对象是联动的
深拷贝:在堆内存中重新开辟一块空间,存放原对象的值,让栈中的引用指向这块新的内存地址,新旧对象不在相互影响
三、实现深拷贝的方式
1. 递归函数调用
const deepClone = (source) => { if (!source && typeof source !== object) { throw new Error(error arguments, deepClone) } const targetObj = source.constructor === Array ? [] : {} Object.keys(source).forEach(keys => { if (source[keys] && typeof source[keys] === object) { targetObj[keys] = deepClone(source[keys]) } else { targetObj[keys] = source[keys] } }) return targetObj }
2. JSON.stringify + JSON.parse
const obj = { name: dd, age: 18, say: { text: hello } } const str = JSON.stringify(obj) let obj2 = JSON.parse(str) obj2.say.text = hi console.log(obj); //{ name: dd, age: 18, say: { text: hello } } console.log(obj2); //{ name: dd, age: 18, say: { text: hi } }
注意:JSON.string实现深拷贝有几个特点:
const obj3 = { func: function () { console.log(1) }, obj: { name: h }, arr: [1, 2, 3], und: undefined, ref: /^123$/, date: new Date(), NaN: NaN, infinity: Infinity, sym: Symbol(1) } console.log(JSON.parse(JSON.stringify(obj3))) // NaN: null // arr: (3) [1, 2, 3] // date: "2023-02-07T10:27:29.165Z" // infinity: null // obj: {name: h} // ref: {}
拷贝的对象的值如果有函数,undefined,symbol 这几种类型,经过 JSON.stringify 序列化后字符串中这个键值对会消失。 拷贝 Date 类型会变成字符串 无法拷贝不可枚举的属性 无法拷贝对象原型链 拷贝 RegExp 引用类型会变成空对象 对象中含有 NaN、infinity 以及 -infinity,JSON 序列化后的结果变成 null
3. lodash (js库)
const _ = require(lodash) const foo = { name: 张三, info: { age: 24 } } const newFoo = _.cloneDeep(foo); foo.info.age = 25 console.log(foo, newFoo) // { name: 张三, info: { age: 25 } } { name: 张三, info: { age: 24 } }
4. Object.assign
注意:只有当对象中没有嵌套对象时,才可以实现深拷贝 const foo = { name: 张三, age: 24 } const newFoo = Object.assign({}, foo) foo.age = 25 console.log(foo, newFoo) // {name: 张三, age: 25} {name: 张三, age: 24} // 对象中有内嵌的对象时 const foo = { name: 张三, info: { age: 24 } } const newFoo = Object.assign({}, foo) foo.info.age = 25 console.log(foo, newFoo) // { name: 张三, info: { age: 25 } } { name: 张三, info: { age: 25 } }
5.structuredClone
const foo = { name: 张三, info: { age: 24 } } const newFoo = structuredClone(foo) // foo.info.age = 25 console.log(foo, newFoo) // { name: 张三, info: { age: 25 } } { name: 张三, info: { age: 24 } }
下一篇:
Apifox接口测试工具使用教程