1、MDN 文档已详细介绍 Object.assign()用法:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Object.assign
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
1
<script>
let obj1 = {name:'山东',id:1,city:{name:'青岛',cityId:'2'}};
let obj2 = Object.assign(obj1);
obj2.city.name = '济南';
obj2.city.cityId = 3;
console.log(obj1); //它将返回目标对象
</script>
Object.assign(target, ...sources)
target:目标对象
sources:源对象
返回值:目标对象
//2、如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。
let obj1 = {name:'山东',id:1};
let obj2 = {name:'青岛',id:2};
let obj3 = Object.assign(obj1,obj2);
console.log(obj1,obj3); //后面的源对象的属性将类似地覆盖前面的源对象的属性。
//3、由于undefined和null无法转成对象,所以如果它们作为参数,就会报错。
Object.assign(undefined) // 报错
Object.assign(null) // 报错
//4、注意:Object.assign 不会在那些source对象值为 null 或 undefined 的时候抛出错误
let obj = {id: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
如果非对象参数出现在源对象的位置(即非首参数),那么处理规则有所不同。首先,这些参数都会转成对象,如果无法转成对象,就会跳过。这意味着,如果undefined和null不在首参数,就不会报错。
//5、 其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。(数值和布尔值都会被忽略。这是因为只有字符串的包装对象,会产生可枚举属性。)
const a = '山东';
const b = true;
const c = 10;
const obj = Object.assign({}, a, b, c);
console.log(obj);
// 6、拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)
const ccc = Object.assign({b: 'c'},
Object.defineProperty({}, 'invisible', {
enumerable: false,
value: 'hello'
})
)
console.log(ccc)
// 7、 属性名为 Symbol 值的属性,也会被Object.assign拷贝。
const ccc = Object.assign({b: 'c'},{ [Symbol('d')]: 'e' })
console.log(ccc)
2、浅拷贝:只针对Object和Array这样的对象数据类型
// 浅拷贝的实现方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>浅/深拷贝</title>
</head>
<body>
</body>
<script>
// 1、直接复制一个变量
let obj1 = {name:'山东',id:1,city:{name:'青岛',cityId:'2'}};
let obj2 = obj1;
obj2.city.name = '济南';
obj2.city.cityId = 3;
console.log(obj1, obj2); // 修改复制的对象会影响原对象
</script>
</html>
// 2、Object.assign() 第一条已介绍
let obj1 = {name:'山东',id:1,city:{name:'青岛',cityId:'2'}};
let obj2 = Object.assign(obj1);
obj2.city.name = '济南';
obj2.city.cityId = 3;
console.log(obj1);
// 3、Array.prototype.concat() 注意: 修改新对象会改到原对象:
let arr = [1, 2, {
name: '山东'
}];
let arr2 = arr.concat();
arr[0] = 8;
arr2[1] = '这是和arr1的区别';
arr2[2].name = '山西';
console.log(arr,arr2);
var arr1 = ["1","2","3"];
var arr2 = arr1.concat();
arr2[1] = "9";
console.log(arr1,arr2); //["1","2","3"] ["1","9","3"];
// 4、Array.prototype.slice() 注意:修改新对象会改到原对象
let arr = [1, 2, {
name: ' 山东'
}];
let arr3 = arr.slice();
arr3[2].name = '山西'
console.log(arr,arr3);
//补充
关于Array的slice和concat方法的补充说明:Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。
如果该元素是个对象引用(不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变
对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组
3、深拷贝
// 深拷贝
// 1、JSON.parse(JSON.stringify())
let arr = [1, 2, {
name: '山东'
}];
let arr3 = JSON.parse(JSON.stringify(arr))
arr3[1] = 6;
arr3[2].name = '山西';
console.log(arr,arr3);
//原理:首先用JSON.stringify()将对象转化成JSON字符串,再用JSON。parse()将字符串解析成对象。
这样新的对象就会产生。而且对象会开辟新的栈。实现了深拷贝。
// 注意:这种方法虽然可以实现数组或者对象的深拷贝,但是不能处理函数
let arr = [1, 2, {
name: '山东'
},function add() {
}];
let arr3 = JSON.parse(JSON.stringify(arr))
arr3[1] = 6;
arr3[2].name = '山西';
console.log(arr,arr3);
// 因为JSON.stringify()方法是将一个对象或者数组转化成一个JSON字符串,不能接收函数