赋值
let obj1={a:1,b:2};
console.log(obj1);//输出{a:1,b:2}
let obj2=obj1;//浅拷贝
console.log(obj2);//输出{a:1,b:2}
obj1.a=5;
console.log(obj1);//输出{a:5,b:2}
console.log(obj2);//输出{a:5,b:2}
浅拷贝
展开语法、Array.prototype.concat()
、Array.prototype.slice()
、Array.from()
、Object.assign()
和 Object.create()
扩展运算符(...)
let obj = {
name: '张三',
age: 23,
address: undefined,
sayHello: function () {
console.log('Hello');
},
isStudent: false,
job: {
name: 'FE',
money: 12
},
[Symbol('sy')]: 13
}
let newObj = { ...obj };
newObj.age = 16;
newObj.job.money = 22;
console.log(obj);//{name: '张三',age: 23, isStudent: false, job: {name: 'FE',money: 22},sayHello:ƒ(),Symbol(sy):13, address: undefined}
console.log(newObj);//{name: '张三',age: 16, isStudent: false, job: {name: 'FE',money: 22},sayHello:ƒ(),Symbol(sy):13, address: undefined}
newObj.sayHello() //Hello
arr.slice(begin, end);
var arr = [2, 4, 6, { y: 10 }]
var newArr = arr.slice()
newArr[0] = 10
newArr[3].x = 20
newArr[3].y = 30
console.log(JSON.stringify(arr)) //[2,4,6,{"y":30,"x":20}]
console.log(JSON.stringify(newArr)) //[10,4,6,{"y":30,"x":20}]
arr.concat()
var arr = ["Chinese", { "name": "zs" }, "French"]
var arr1 = arr.concat()
arr1[1].name = "ls"
arr1[2] = "China"
console.log(JSON.stringify(arr)); //["Chinese",{"name":"ls"},"French"]
console.log(JSON.stringify(arr1)); //["Chinese",{"name":"ls"},"China"]
Object.assign(target, …sources)
let obj = {
name: '张三',
age: 23,
address: undefined,
sayHello: function () {
console.log('Hello');
},
isStudent: false,
job: {
name: 'FE',
money: 12
},
[Symbol('sy')]: 13
}
var newObj = {}
Object.assign(newObj, obj)
newObj.age = 16;
newObj.job.money = 22;
console.log(obj);//{name: '张三',age: 23, isStudent: false ,job: {name: 'FE',money: 22},sayHello:ƒ(),Symbol(sy):13, address: undefined}
console.log(newObj);//{name: '张三',age: 16, isStudent: false, job: {name: 'FE',money: 22,,sayHello:ƒ(),Symbol(sy):13, address: undefined}}
newObj.sayHello() //Hello
由上案例可以看出,扩展运算符(...)、concat、slice、assign只对obj对象中属性为基本数据类型的值进行了深拷贝,引用类型的值为浅拷贝。
深拷贝
第一种:配合使用JSON.parse()和JSON.stringify()两个函数(局限性比较大)
- 会忽略属性值为undefined的属性
- 会忽略属性为Symbol的属性
- 不会序列化函数和正则表达式类型
- 会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object
- 不能解决循环引用的问题,直接报错
let obj = {
name: '张三',
age: 23,
address: undefined,
sayHello: function () {
console.log('Hello');
},
isStudent: false,
job: {
name: 'FE',
money: 12
},
[Symbol('sy')]:13
}
let newObj = JSON.parse(JSON.stringify(obj));
obj.job.money = 21;
console.log(JSON.stringify(obj)); //{"name":"张三","age":23,"isStudent":false,"job":{"name":"FE","money":21}}
console.log(newObj.name); // 输出张三
console.log(newObj.age); // 输出23
console.log(newObj.job.money); // 输出12
console.log(newObj.address); // 报错
console.log(newObj.sayHello());// 报错 Uncaught TypeError: newObj.sayHello is not a function
第二种: 实现自己简易的深拷贝函数
//此写法会忽略属性为Symbol的属性
function deepClone(obj) {
if (typeof obj !== "object") return;
let newObj = obj instanceof Array ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key];
}
}
return newObj;
}
// 不忽略Symbol
function deepClone(obj){
if (typeof obj !== "object") return;
let newObj = obj instanceof Array ? [] : {};
for (var i = 0; i < Reflect.ownKeys(obj).length; i++) {
let key = Reflect.ownKeys(obj)[i]
if(obj.propertyIsEnumerable(key)){
newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key];
}
}
return newObj;
}
let obj = {
name: '张三',
age: 23,
address: undefined,
sayHello: function () {
console.log('Hello');
},
isStudent: false,
job: {
name: 'FE',
money: 12
},
[Symbol('sy')]: 13
}
let newObj = deepClone(obj);
console.log(newObj);
console.log(newObj.name); // 输出张三
console.log(newObj.age); // 输出23
console.log(newObj.job.money); // 输出12
console.log(newObj.address); // undefined
console.log(newObj.sayHello());// 报错 Uncaught TypeError: newObj.sayHello is not a function
第三种方法:函数库lodash的 _.cloneDeep 方法
let obj = {
name: '张三',
age: 23,
isStudent: false,
job: {
name: 'FE',
money: 12
}
}
let newObj = _.cloneDeep(obj);
obj.job.money = 21;
console.log(newObj.name); // 输出张三
console.log(newObj.age); // 输出23
console.log(newObj.job.money);// 输出12
第四种:jQuery.extend()方法
jQuery有提供一个 .extend(deepCopy, target, object1, [objectN]) //第一个参数为true,就是深拷贝
let obj = {
a: {
c: 1,
d: [1, 3, 5],
},
b: 2
}
let newObj = $.extend(true, {}, obj);
obj.b = 20;
console.log(newObj.b); //输出2
第五种 JS原生的深拷贝:structuredClone()
- Function 类型会报错
let obj = {
name: '张三',
age: 23,
address: undefined,
a:null,
b:new Date(),
c:new RegExp(/\d/),
d:new Error('dd'),
isStudent: false,
job: {
name: 'FE',
money: 12
},
[Symbol('sy')]: 13
}
let newObj = structuredClone(obj);