深拷贝和浅拷贝的具体意义就不解释了,在工作之前一直知道深拷贝和浅拷贝,但是仅限知道,在自学过程中没有具体使用过。然后导致在看代码的时候遇见json.parse(json.string(对象名))这样一句我还很纳闷这样对象->字符串->对象颠倒一下有什么意义,还去问了辅导员。为了防止类似情况再次发生,在这里做个深拷贝和浅拷贝的总结,方便以后学习。
赋值(非浅拷贝)
简单的引用赋值
let a = {
name: 'aa',
age: '18',
getName(){
return this.name
}
}
let b = a
b.name = 'bb'
console.log(a,b);
//结果为
//{ name: 'bb', age: '18', getName: [Function: getName] }
//{ name: 'bb', age: '18', getName: [Function: getName] }
浅拷贝的实现方式
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址
即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址。
1.Object.assign()
let a = {
name: 'aa',
age: '18',
children: {
sex: '男'
},
getName(){
return this.name
}
}
let b = Object.assign({},a)
b.name = 'bb' // b改变一级属性
b.children.sex = '女' // b改变二级属性
console.log(a,b);
结果为:
{
name: 'aa', // 发现a一级属性没有发生改变
age: '18',
children: { sex: '女' }, // 发现a二级属性已经发生改变
getName: [Function: getName]
}
{
name: 'bb',
age: '18',
children: { sex: '女' },
getName: [Function: getName]
}
2.es6的展开语法
let a = {
name: 'aa',
age: '18',
children: {
sex: '男'
},
getName(){
return this.name
}
}
let b = {...a}
b.name = 'bb' // b改变一级属性
b.children.sex = '女' // b改变二级属性
console.log(a, b);
结果为:
{
name: 'aa', // a的一级属性没有改变
age: '18',
children: { sex: '女' }, // a的二级属性发生的改变
getName: [Function: getName]
} {
name: 'bb',
age: '18',
children: { sex: '女' },
getName: [Function: getName]
}
3.数组名.slice()和 数组名.concat()
数组是一种独特的对象
slice方法
let arrA = [1, 2, 3, 4, [1, 2, 3]]
let arrB = arrA.slice()
arrB[0] = 'a' // arrB改变一级属性
arrB[4][0] = 'a' // arrB改变二级属性
console.log(arrA, arrB);
结果为:
[ 1, 2, 3, 4, [ 'a', 2, 3 ] ] // arrA一级属性没有被改变,二级属性发生了改变
[ 'a', 2, 3, 4, [ 'a', 2, 3 ] ]
concat方法
let arrA = [1, 2, 3, 4, [1, 2, 3]]
let arrB = arrA.concat()
arrB[0] = 'b' // arrB改变一级属性
arrB[4][0] = 'b' // arrB改变二级属性
console.log(arrA, arrB);
结果为:
[ 1, 2, 3, 4, [ 'b', 2, 3 ] ] // arrA一级属性没有改变,二级属性发生了改变
[ 'b', 2, 3, 4, [ 'b', 2, 3 ] ]
深拷贝的实现方式
1,暴力美学,使用递归函数
2,使用JSON.parse(JSON.stringify(对象))方法
就是我在公司遇见的代码。但是这种方法不能复制原对象里的函数。并且原属性的一级属性和二级属性都不发生改变。
let a = {
name: 'aa',
age: '18',
children: {
sex: '男'
},
getName(){
return this.name
}
}
let b = JSON.parse(JSON.stringify(a))
b.name = 'bb' // b改变一级属性
b.children.sex = '女' // b改变二级属性
console.log(a, b);
//结果为
//{
// name: 'aa', // a一级属性没有发生改变
// age: '18',
// children: { sex: '男' }, // a二级属性也没有改变
// getName: [Function: getName]
//}
//{ name: 'bb', age: '18', children: { sex: '女' } } // function函数没有了
但是这种方式存在弊端,会忽略undefined、symbol和函数
const obj = {
name: 'A',
name1: undefined,
name3: function() {},
name4: Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}
3.使用lodash提供的方法
const _ = require('lodash');
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
const obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
4.使用jQuery提供的方法
const $ = require('jquery');
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
const obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false