目录
1、数据类型
1.1、基本数据类型
基本数据类型将数据以名-值的方式存储在栈内存中。基本数据类型主要有6种:
- String
- Number
- Boolean
- null
- Undefined
- symbol
基本数据类型的拷贝都是深拷贝
1.2、引用数据类型
引用数据类型的存储相对复杂一点,以名-引用地址-值,名存在栈内存中,值存在堆内存中,栈内存提供一个引用地址指向堆内存中的值。引用数据类型主要有3种:
- Object
- Array
- Function
引用数据类型的变量是一个指向堆内存中实际对象的引用,变量以及指向堆内存的指针存在在栈内存中
引用数据类型的拷贝分为浅拷贝和深拷贝
2、概念
在JavaScript中,对对象或数据的复制分为深拷贝和浅拷贝。
2.1、浅拷贝:创建一个指向原始对象的新对象的引用
引用数据类型的浅拷贝,会创建一个新对象或数据结构,其中包含原始对象的引用。换句话说,新对象与原始对象共享相同的内存地址,因此对其中一个对象进行更改会影响到另一个对象。浅拷贝仅复制对象的第一层结构,而不会递归复制嵌套的对象或数据。
var a = [1, 2, 3]
var b = a
console.log(a, b) // a: [1, 2, 3] b:[1, 2, 3]
a[0] = 4
console.log(a, b) // a: [4, 2, 3] b:[4, 2, 3]
b[0] = 5
console.log(a, b) // a: [5, 2, 3] b:[5, 2, 3]
2.2、深拷贝:创建一个全新的对象及其所有关联的对象
引用数据类型的深拷贝创建一个全新的对象或数据结构,其中包含原始对象完全独立的副本。新对象与原始对象具有不同的内存地址,因此彼此之间的更改是相互独立的。深拷贝会递归复制所有嵌套的对象或数据,确保整个对象及其子对象都被复制。
const deepCopy = (obj) => { // 数组对象深拷贝
let objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === 'object') {
for (let key in obj) {
if (obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepCopy(obj[key]);
} else {
objClone[key] = obj[key]
}
}
}
return objClone;
}
let obj = {
a: 'hello',
b: 'world'
}
let newObj = deepCopy(obj)
newObj.b = 'JavaScript'
console.log(obj, newObj) // {a: 'hello', b: 'world'} {a: 'hello', b: 'JavaScript'}
3、实现方式
3.1、浅拷贝
- 直接赋值
var obj = {
a: 1
}
var newObj = obj
newObj.a = 2
console.log(obj, newObj)// {a: 2} {a: 2}
- Object.assign(target,source)
let obj = {
name: 'xiaolu',
age: 18,
address:{
city: 'Guangzhou',
area: 'panyu'
}
};
const newObj = Object.assign({}, obj);
newObj.address.city = 'Beijing';
console.log(obj, newObj); // {name:'xiaolu', age: 18,address:{city: 'Beijing',area: 'panyu'}} {name:'xiaolu', age: 18,address:{city: 'Beijing',area: 'panyu'}}
- 拓展运算符:…
const obj = {
name: 'xiaolu',
age: 18,
};
const newObj = {...obj};
newObj.age = 20;
console.log(obj, newObj); // {name:'xiaolu', age: 20,} {name:'xiaolu', age: 20}
- Array.slice(begin, end)
const arr = [
{
name: '张三',
age: 30,
}
];
const newArr = arr.slice()
newArr[0].name = '张三丰';
console.log(arr, newArr); // [{name: '张三丰',age: 30}] [{name: '张三丰',age: 30}]
- Array.concat()
const arr = [
{
name: '张三',
age: 30,
},
];
const newArr = arr.concat([])
newArr[0].name = '张三丰';
console.log(arr, newArr); // [{name: '张三丰',age: 30}] [{name: '张三丰',age: 30}]
3.2、深拷贝
- JSON.parse(JSON.stringify())
var arr = ['a', 'b', [1, 2]];
var str = JSON.stringify(arr);
var col = JSON.parse(str);
console.log(col); // ["a","b",Array(2)]
arr[2][0] = 'x';
console.log( col[2][0] ); // 1
无法拷贝undefined、函数、正则表达式等特殊对象。
无法处理循环引用的情况
- 递归
const deepCopy = (obj) => { // 数组对象深拷贝
let objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === 'object') {
for (let key in obj) {
if (obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepCopy(obj[key]);
} else {
objClone[key] = obj[key]
}
}
}
return objClone;
}
let obj = {
a: 'hello',
b: 'world'
}
let newObj = deepCopy(obj)
newObj.b = 'JavaScript'
console.log(obj, newObj) // {a: 'hello', b: 'world'} {a: 'hello', b: 'JavaScript'}
无法拷贝循环引用的情况
- 第三方库
除了以上两种方式,还有一些比较好的第三方库也可以实现深拷贝,如jQuery、lodash等。
const obj = {
name: '张三',
age: 30,
};
const newObj = _.cloneDeep(obj)
newArr[0].name = '张三丰';
console.log(obj, newObj); // [{name: '张三',age: 30}] [{name: '张三丰',age: 30}]