目录
一、前置知识详解
1.1.JavaScript数据类型
1.2.理解传值和传址
二、浅拷贝
2.1.浅拷贝的定义和原理
2.2.实现浅拷贝的方法
2.2.1.手写递归实现
2.2.2.利用展开语法实现浅拷贝
2.2.3.Object.assign进行对象的合并
2.2.4.利用Array.prototype.,slice()
2.2.5.利用Array.prototype.contact()
三、深拷贝
3.1.深拷贝的定义及原理
3.2.深拷贝的实现方法
3.2.1.递归实现深拷贝
3.2.2.JSON.parse(JSON.stringify(待拷贝对象)
3.2.3.jQuery 中的 $.extend() 第一个参数设置为true为深拷贝,为false为浅拷贝(要引入JQuery库)
3.2.4.引入loadsh,提供 cloneDeep 实现
一、前置知识详解
在学习浅拷贝和深拷贝之前,我们有必要了解的前置知识
1.1.JavaScript数据类型
JavaScript的数据类型分为基本类型:Number,String,Boolean,Undefined,Null,Symbol,BigInt
引用l类型:对象(Object),数组(Array),函数(Function)
基本类型数据保存在在栈内存中
引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中
1.2.理解传值和传址
传值:开辟新内存区域存储值
代码示例如下
let a = 3;let b = a;console.log(a, b); // 3 3b = 5; console.log(a, b); // 3 5
传址:传递内存地址,而不开辟新空间
let obj = {name: 'zs',age: 20,};let obj1 = obj;console.log(obj, obj1);obj1.name = 'lisi';console.log(obj, obj1);
输出内容相同,obj和obj1指向了同一个内存地址。
二、浅拷贝
2.1.浅拷贝的定义和原理
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址
即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址
2.2.实现浅拷贝的方法
2.2.1.手写递归实现
// 手写实现浅拷贝function shallowClone(obj) {let newObj = {};for (let i in obj) {// 只要是obj的属性,直接复制一份给newObjif (obj.hasOwnProperty(i)) {newObj[i] = obj[i];}}return newObj;}const person = {name: 'zs',hobby: ['排球', '网球', '篮球'],};const person1 = shallowClone(person);console.log(person);console.log(person1);person1.name = 'lisi';person1.hobby[0] = '足球';console.log(person);console.log(person1);
打印输出结果如下
2.2.2.利用展开语法实现浅拷贝
let obj = {name: 'zs',lessons: ['hobby', 'suxexu', 'kligh'],};let hd1 = { ...obj };hd1.name = 'lisi';hd1.lessons[0] = 'math';console.log(obj);console.log(hd1);
2.2.3.Object.assign进行对象的合并
let obj = {name: 'zs',lessons: ['hobby', 'suxexu', 'kligh'],};let newObj = Object.assign({}, obj);newObj.lessons[0] = 'math';console.log(obj);console.log(newObj);
2.2.4.利用Array.prototype.,slice()
const arr = [1, 2, { name: 'nordon' }];const newArr = arr.slice();newArr[2].name = 'wy';console.log(arr);console.log(newArr);
2.2.5.利用Array.prototype.contact()
const arr = [1, 2, { name: 'nordon' }];const newArr = arr.concat();newArr[2].name = 'wy';console.log(arr);console.log(newArr);
三、深拷贝
3.1.深拷贝的定义及原理
深拷贝开辟一个新的栈,两个对象属性完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
3.2.深拷贝的实现方法
3.2.1.递归实现深拷贝
第一种方法
function deepClone(obj) {let newObj = obj instanceof Array ? [] : {};for (let i in obj) {if (obj.hasOwnProperty(i)) {if (obj[i] && typeof obj[i] == 'object') {// 若对象属性还是引用类型,进行递归newObj[i] = deepClone(obj[i]);} else {// 对象属性为基础数据类型,直接赋值newObj[i] = obj[i];}}}return newObj;}const obj = {name: 'zs',hobby: ['排球', '网球', '乒乓球'],};const newObj = deepClone(obj);newObj.name = 'lisi';newObj.hobby[0] = '篮球';console.log(obj);console.log(newObj);
第二种方法,巧妙运用Object.entries(obj)遍历对象的属性和值
function deepClone(obj) {let newObj = obj instanceof Array ? [] : {};for (const [k, v] of Object.entries(obj)) {newObj[k] = typeof v == 'object' ? deepClone(v) : v;}return newObj;}const obj = {name: 'zs',hobby: ['排球', '网球', '乒乓球'],};const newObj = deepClone(obj);newObj.name = 'lisi';newObj.hobby[0] = '篮球';console.log(obj);console.log(newObj);
输出结果相同,如下:
3.2.2.JSON.parse(JSON.stringify(待拷贝对象)
const obj = {name: 'zs',hobby: ['排球', '网球', '乒乓球'],};const newObj = JSON.parse(JSON.stringify(obj));newObj.name = 'lisi';newObj.hobby[0] = '篮球';console.log(obj);console.log(newObj);
3.2.3.jQuery 中的 $.extend() 第一个参数设置为true为深拷贝,为false为浅拷贝(要引入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);
3.2.4.引入loadsh,提供 cloneDeep 实现
vue中使用loash库实现深拷贝的步骤
- 安装loadsh npm i --save lodash
- 引入loadsh import _ from 'lodash'
- 直接调用loadsh库的方法 const newObj = _.cloneDeep(this.obj)