先放出实现浅拷贝和深拷贝的一些方法(直接食用):
1.浅拷贝:
浅拷贝在拷贝对象的时候,对于对象最外一层实现的是普通的值拷贝,对于对象里面的对象是浅拷贝,只复制地址不复制地址对应的值。
/*
方法1.1:扩展运算符(最简单的方式)
*/
const originalObject = { a: 1, b: 2, c: {d: 3} };
const shallowCopy = { ...originalObject };
originalObject.a = 10;
console.log(originalObject.a); // 输出 10
console.log(shallowCopy.a); // 输出 1
originalObject.c.d = 11;
console.log(shallowCopy.c.d); // 输出 11
console.log(originalObject.c.d); // 输出 11
/*
方法2:Object.assign()
*/
const originalObject = { a: 1, b: 2, c: { d: 3} };
const shallowCopy = Object.assign({}, originalObject);
originalObject.a = 10;
originalObject.c.d = 11;
console.log(originalObject.a); // 输出 10
console.log(shallowCopy.a); // 输出 1
console.log(originalObject.c.d); // 输出 11
console.log(shallowCopy.c.d); // 输出 11
/*
方法1.3:自定义函数实现浅拷贝
*/
function shallowCopyFun(obj) {
// 只拷贝对象
if (typeof obj !== 'object' || obj === null) {
return obj;
}
// 根据 obj 的类型决定新对象是数组还是对象
let newObj = Array.isArray(obj) ? [] : {};
// 遍历 obj,并复制其自身属性到新对象
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
const originalObject = { a: 1, b: 2, c: { d: 3,e: 4 } };
const shallowCopy = shallowCopyFun(originalObject);
originalObject.a = 10;
console.log(shallowCopy.a); // 输出 1
console.log(originalObject.a); // 输出 10
originalObject.c.d = 11;
console.log(shallowCopy.c.d); // 输出 11
console.log(originalObject.c.d); // 输出 11
2.深拷贝
/*
方法2.1:Json对象实现深拷贝
JSON 序列化和反序列化
*/
const originalObject = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(originalObject));
originalObject.b.c = 10;
console.log(originalObject.b.c); // 输出 10
console.log(deepCopy.b.c); // 输出 2
/*
方法2.2:递归函数实现
*/
function deepCopyFun(obj) {
// 检查值是否是引用类型
if (typeof obj !== "object" || obj === null) {
return obj;
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags);
}
if (obj instanceof Function) {
return obj;
}
// 初始化一个新的数组或对象
let newObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
// 确保属性属于对象本身,不是继承的
if (obj.hasOwnProperty(key)) {
// 递归复制每个属性
newObj[key] = deepCopyFun(obj[key]);
}
}
return newObj;
}
const originalObject = { a: 1, b: { c: 2 } };
const deepCopy = deepCopyFun(originalObject);
originalObject.b.c = 10;
console.log(originalObject.b.c); // 输出 10
console.log(deepCopy.b.c); // 输出 2
/*
方法2.3:concat实现深拷贝
concat(arr1, arr2,...)
*/
var arr = [1,2,3]
var newArr = [].concat(arr)
arr.push(4)
console.log('arr:', arr);
console.log('newArr:', newArr);
/*
arr: [ 1, 2, 3, 4 ]
newArr: [ 1, 2, 3 ]
*/
/*
方法2.4:slice实现深拷贝
slice(idx1, idx2)
*/
var arr = [1,2,3]
var newArr = arr.slice()
arr.push(4)
console.log('arr:', arr);
console.log('newArr:', newArr);
/*
arr: [ 1, 2, 3, 4 ]
newArr: [ 1, 2, 3 ]
*/
/*
方法2.5:lodash实现深拷贝
_.cloneDeep(value)
value : 要深拷贝的值。
返回拷贝后的值
vue 中使用 :
a. npm i --save lodash 下载依赖
b. import _ from 'lodash' 在 组件 中引入
c. 用法和下面的一样
*/
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
/*
方法2.6:扩展符实现深拷贝
*/
var a=[1,2,3]
var b=[...a];
b.push(4);
console.log(b);//1,2,3,4
console.log(a)//1,2,3
为什么会有浅拷贝和深拷贝?这要从javaScript
数据类型说起。分为基本数据类型和引用数据类型。
基本类型数据都是按照值访问的,直接保存和修改在变量里面实际的值。
值类型:在存储变量中存储的是值的本身,因此叫做值类型,即string
,Number
,Boolean
,Undefined
,Null
其中,基本数据类型null
返回的是一个空的对象object
,如果有一个变量我们以后打算存储为对象,默认值可以设置成null
。
引用类型数据是按照引用访问的,即保存在变量对象中的是一个地址,该地址与堆内存的实际值相关联。
引用数据类型在存储变量中存储的仅仅是地址(引用),因此叫做引用数据类型。即通过new
关键字创建的对象(系统对象、自定义对象),如Object
、Array
、Date
等。
操作系统控制栈,但是它不控制堆。具体堆栈理解可以自行bing!
引用类型的值是同时保存在栈内存和堆内存中的对象javascript
不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,那我们操作啥呢? 实际上,是操作对象的引用, 所以引用类型的值是按引用访问的。 准确地说,引用类型的存储需要内存的栈区和堆区(堆区是指内存里的堆内存)共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址。
基本数据类型-在百度上大多数都是说存在栈中的。从知乎回答找到正确答案link。即:
字符串: 存在堆里,栈中为引用地址,如果存在相同字符串,则引用地址相同。
数字: 小整数存在栈中,其他类型存在堆中。
其他类型:引擎初始化时分配唯一地址,栈中的变量存的是唯一的引用。
所以这里我们在来说说深拷贝和浅拷贝的区别: