拷贝
Object.assign
Object.assign(obj1,obj2,obj3,…)
作用:实现多个对象之间的合并/替换
- 用 obj2 中的每一项替换 obj1「obj1被更改」
- 再用 obj3 中的每一项替换被更改后的 obj1 「obj1有被修改了」
- …
最后修改的是obj1,assign 返回的也是 obj1 的内存地址
替换规则:
obj2替换obj1
1和2都有的,以2为主
- 1有2没有的,保留1的内容
1没有2有的,给1中新设置这个成员
let obj1 = {x: 10,y: 20}let obj2 = {x: 100,m: 30}let obj3 = {x: 1000,n: 40}let obj = Object.assign(obj1, obj2, obj3)console.log(obj) //{ x: 1000, y: 20, m: 30, n: 40 }console.log(obj1) //{ x: 1000, y: 20, m: 30, n: 40 }console.log(obj1 === obj) //trueconsole.log(obj2, obj3) //没有更改过
Object.assign 采用的是浅比较/浅合并let obj1 = {x: 10,y: {n: 20}}let obj2 = {z: 30,y: {m: 1000}}Object.assign(obj1, obj2)console.log(obj1) // { x: 10, y: { m: 1000 }, z: 30 }
实现 obj2 替换 obj1,但是不想修改 obj1 的内容「想实现对象的合并,但是不想改变任意一个对象,想返回一个新对象即可」let obj1 = {x: 10,y: 20}let obj2 = {x: 100,m: 30}let obj = Object.assign({}, obj1, obj2)console.log(obj, obj1, obj2)
数组/对象的拷贝(克隆)
数组的浅拷贝
arr.slice()
- […arr]
- arr.concat()
- 迭代赋值
- Object.assign([],arr)
- … ```javascript let arr1 = [10, [20, 30, [40, 50]]]
let arr2 = arr1.slice() let arr2 = […arr1] let arr2 = arr1.concat() let arr2 = [] arr1.forEach(item => { arr2.push(item) })
let arr2 = Object.assign([], arr1) console.log(arr2 === arr1) //fasle console.log(arr2[1] === arr1[1]) //true
<a name="d7AjV"></a>#### 对象的浅拷贝- { ...obj }- Object.assign({}, obj)- 迭代对象每一项,赋值给新对象- ...```javascriptlet obj1 = {x: 10,y: {z: 20}}let obj2 = { ...obj1 }let obj2 = Object.assign({}, obj1)let obj2 = {}Reflect.ownKeys(obj1).forEach(key => {obj2[key] = obj1[key]})console.log(obj1, obj2)console.log(obj2 === obj1) //fasleconsole.log(obj2.y === obj1.y) //true
浅拷贝的特点:
原始对象(A)和拷贝后的新对象(B),首先是不同的堆内存,只是第一级的内容相同,但是A和B会共用第二级及更深层级的内存,没有实现完全断开联系…
![7~GL~NU}_]%1O)E0$QRVY3_tmb.jpg
但是真实项目中,往往需要的不是浅拷贝,而是深拷贝,让拷贝后的对象和原来的对象彻底断开联系
浅拷贝和深拷贝的区别
- 浅拷贝:只拷贝第一级
- 深拷贝:所有级别都需要拷贝,拷贝成全新的内存空间(只不过内容一样)
深拷贝的方案:
基于 JSON 对象中的方法进行处理
- 先基于 JSON.stringify 把原来的对象变为“json字符串”
然后再基于 JSON.parse 把“json字符串”变为对象「此时会重新开辟“所有”需要的内存空间」
let obj1 = {x: 10,y: [1, 2, { z: 3 }],m: {n: 20,k: {p: 30}}}let obj2 = JSON.parse(JSON.stringify(obj1))console.log(obj2)console.log(obj2 === obj1) //falseconsole.log(obj2.m === obj1.m) //falseconsole.log(obj2.m.k === obj1.m.k) //falseconsole.log(obj2.y === obj1.y) //falseconsole.log(obj2.y[2] === obj1.y[2]) //false
但是 JSON 这种方案存在弊端(在基于 stringify 把对象变为字符串的时候):
无法处理 BigInt 类型的值
- 属性名是 symbol 类型,或者属性值是 undefined、symbol、function 类型的,都自动消失了
- 属性值是 正则/Error 的实例,都自动变为 {}
- 日期对象变为字符串后,再基于 parse 处理的时候,回不到对象格式了
- 不支持对象的“套娃”操作(这里window就是典型套娃 window.window===window)

也就是JSON这种方案,只能用于处理:属性名是字符串、属性值是“数字、字符串、布尔、null、普通对象、数组对象”、而且没有套娃操作…这样的情况!!
let obj = {name: '珠峰',age: 13,bool: true,n: null,u: undefined,sym: Symbol('sym'),big: 10n,list: [10, 20, { a: 100, b: 200 }],reg: /\d+/,time: new Date,err: new Error('xxx'),ke: { js: '基础课', web: '高级课', arr: [1000, 2000] },[Symbol('KEY')]: 100,fn: function () { }}obj.obj = objlet newObj = _.cloneDeep(obj)console.log(newObj)console.log(newObj === obj)console.log(newObj.ke.arr === obj.ke.arr)
基于循环和递归,一层层的进行拷贝
先放一个大概意思代码 后面完善~~
function deepCloneArray(arr) {var clonedArray = [];for (var i = 0; i < arr.length; i++) {var item = arr[i];if (Array.isArray(item)) {clonedArray.push(deepCloneArray(item)); // 递归处理数组} else if (typeof item === 'object' && item !== null) {clonedArray.push(deepCloneObject(item)); // 递归处理对象} else {clonedArray.push(item);}}return clonedArray;}function deepCloneObject(obj) {var clonedObj = {};for (var key in obj) {var value = obj[key];if (Array.isArray(value)) {clonedObj[key] = deepCloneArray(value); // 递归处理数组} else if (typeof value === 'object' && value !== null) {clonedObj[key] = deepCloneObject(value); // 递归处理对象} else {clonedObj[key] = value;}}return clonedObj;}
合并
let obj1 = {name: '张三',age: 25,hobby: {music: 100,jump: 80}}let obj2 = {name: '李四',age: 22,sex: 0,hobby: {read: 100,music: 90}}let obj3 = {name: '王五',age: 20,height: '158cm',score: {math: 100,chinese: 90}}
