JS学习笔记(九)
本系列更多文章,可以查看专栏 JS学习笔记
文章目录
JS学习笔记(九)一、赋值&复制二、浅拷贝(shallow copy)1. 什么是浅拷贝2. 数组的浅拷贝(1)介绍(2)数组浅拷贝的常见方法 2. 对象的浅拷贝的常见方法 三、深拷贝1. 什么是深拷贝2. 深拷贝介绍3. 深拷贝的常见方法 四、浅拷贝和深拷贝对比结尾一、赋值&复制
此部分赋值和复制的区别,仅针对引用类型
let arr = [1, 3, 5, 7, 9];// 赋值,没有创建新对象let arr2 = arr;// 复制,会创建一个新对象let arr3 = arr.slice();// 输出数组console.log("arr:", arr);console.log("赋值arr2:", arr2);console.log("复制arr3:", arr3);// 比较数组对象console.log("arr === arr2:", arr === arr2);console.log("arr === arr3:", arr === arr3);
输出结果如下图所示:
区别:
1.赋值:仅仅将arr开辟的空间,给arr2进行共享2.复制:重新为数组存储的元素开辟空间,只是元素值相同
深拷贝和浅拷贝,对于数组元素为原始类型(Number、String等)时,没有什么区别,区别在于元素为对象类型。
二、浅拷贝(shallow copy)
一般来说,
(1)原始类型(Number、String、BinInt、Null、Undefined、Boolean)的值存储在栈内存中(闭包除外);
(2)引用类型(Array、Function、Object),值一般存储在堆内存中(JS不允许直接访问堆内存)。
1. 什么是浅拷贝
浅拷贝,指会对引用类型对象本身进行复制,但不会复制对象内部的属性或元素。
注: 如果引用类型对象是数组类型,且其中存储的数据类型是原始类型,则浅拷贝或深拷贝效果一致【将在本文最后进行展示】
2. 数组的浅拷贝
(1)介绍
const arr = [{name: "张三" }, {name: "李四" }];const arr2 = arr.slice();// 输出数组console.log(arr);console.log(arr2);// 比较数组引用值console.log("arr === arr2", arr === arr2);// 比较数组属性值console.log("arr[0] === arr2[0]", arr[0] === arr2[0]);console.log("arr[1] === arr2[1]", arr[1] === arr2[1]);
数组的浅拷贝,如下图所示:
观察上图运行结果可知,浅拷贝仅会创建一个新数组(新的堆地址)存储原数组的值,本质上内部存储的元素是同一个。
(2)数组浅拷贝的常见方法
const arr = [{name: "张三" }, {name: "李四" }];
方式1:Array.slice()方法
const arr2 = arr.slice();
方式2:Array.prototype.concat()方法
const arr2 = arr.concat();
方式3:ES6拓展运算符...
用途:用于将数组转换成以逗号分隔开的参数序列
const arr2 = [...arr];
方式4:for循环、for-of循环、while循环等
注:以下仅为一维数组示例代码
// for循环const arr2 = [];for (let i = 0; i < arr.length; i++) {arr2[i] = arr[i];}// for-of循环const arr2 = [];let i = 0;for (let value of arr) {arr2[i++] = value;}// while循环const arr2 = [];let i = -1;while (++i < arr.length) {arr2[i] = arr[i];}
方式5:Object.assign()方法
用途:将一个或多个源对象,复制给目标对象,返回修改后的对象
const arr2 = Object.assign([], arr);
更多常见方法待补充中…
2. 对象的浅拷贝的常见方法
本质上与数组的浅拷贝一致
对象浅拷贝测试代码,运行结果如下图所示
const obj = {arr1: [1, 3, 5], arr2: [2, 4, 6] };
方式1:ES6拓展运算符...
const obj2 = {...obj };
方式2:Object.assign()方法
用途:将一个或多个源对象,复制给目标对象,返回修改后的对象
const obj2 = Object.assign({}, obj);
更多常见方法待补充中…
三、深拷贝
1. 什么是深拷贝
深拷贝,指不仅复制引用类型对象本身,还会对对象的属性或元素进行复制
注: 如果引用类型对象是数组类型,且其中存储的数据类型是原始类型,则浅拷贝或深拷贝效果一致【将在本文最后进行展示】
2. 深拷贝介绍
以下为数组类型深拷贝为例,进行简单介绍
const arr = [{name: "张三" }, {name: "李四" }];const arr2 = structuredClone(arr);// 输出数组console.log(arr);console.log(arr2);// 比较数组引用值console.log("arr === arr2", arr === arr2);// 比较数组元素console.log("arr[0] === arr2[0]", arr[0] === arr2[0]);console.log("arr[1] === arr2[1]", arr[1] === arr2[1]);// 比较数组元素值console.log("arr[0].name === arr2[0].name ",arr[0].name === arr2[0].name);
数组的深拷贝,如下图所示:
上图可以看出,不仅对象本身进行了复制,其元素也进行了复制
观察上图运行结果可知,深拷贝不仅引用值会复制,其元素的值也会进行复制,仅有不可修改的原始类型的值及其地址不变。
3. 深拷贝的常见方法
const arr = [{name: "张三" }, {name: "李四" }];
方式1:window.structuredClone()方法
【适用于Array和Object】
const arr2 = structuredClone(arr); // window可省略
若对象的属性或者元素为自定义对象,则使用window.structuredClone()
进行深拷贝后会变成普通对象
方式2:利用JSON.parse()和JSON.stringify()方法
【适用于Array和Object】
const arr2 = JSON.parse(JSON.stringify(arr));
更多常见方法待补充中…
四、浅拷贝和深拷贝对比
上文中反复提到,当数据类型是原始类型,则浅拷贝或深拷贝效果一致
下文中,以对象中属性为原始类型为例
const obj = {name: "Jack", age: 18 };// 浅拷贝const obj2 = Object.assign({}, obj);// 深拷贝const obj3 = JSON.parse(JSON.stringify(obj));// 输出对象console.log("obj", obj);console.log("obj2", obj2);console.log("obj3", obj3);// 比较对象引用值console.log("obj === obj2", obj === obj2);console.log("obj === obj3", obj === obj3);// 比较对象中的属性值console.log("obj.name === obj2.name", obj.name === obj2.name);console.log("obj.name === obj3.name", obj.name === obj3.name);
以上代码,运行效果如下图所示:
结尾
部分内容参考《ECMAScript 6 入门》《JavaScript权威指南》《JavaScript高级程序设计》,如有错误,欢迎评论区指正。