深浅拷贝详解
深浅拷贝
经典真题
- 深拷贝和浅拷贝的区别?如何实现
深拷贝和浅拷贝概念
首先,我们需要明确深拷贝和浅拷贝的概念。
-
浅拷贝:只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做浅拷贝(浅复制)。浅拷贝只复制指向某个对象的指针(引用地址),而不复制对象本身,新旧对象还是共享同一块内存。
-
深拷贝:在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响。
浅拷贝方法
接下来我们来看一下对象有哪些浅拷贝方法。
1. 直接赋值
直接赋值是最常见的一种浅拷贝方式。例如:
var stu = {name: 'xiejie',age: 18
}
// 直接赋值
var stu2 = stu;
stu2.name = "zhangsan";
console.log(stu); // { name: 'zhangsan', age: 18 }
console.log(stu2); // { name: 'zhangsan', age: 18 }
2. Object.assign 方法
我们先来看一下 Object.assign 方法的基本用法。
该方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。
如下:
var stu = {name: 'xiejie'
}
var stu2 = Object.assign(stu, { age: 18 }, { gender: 'male' })
console.log(stu2); // { name: 'xiejie', age: 18, gender: 'male' }
在上面的代码中,我们有一个对象 stu,然后使用 Object.assign 方法将后面两个对象的属性值分配到 stu 目标对象上面。
最终得到 { name: ‘xiejie’, age: 18, gender: ‘male’ } 这个对象。
通过这个方法,我们就可以实现一个对象的拷贝。例如:
const stu = {name: 'xiejie',age: 18
}
const stu2 = Object.assign({}, stu)
stu2.name = 'zhangsan';
console.log(stu); // { name: 'xiejie', age: 18 }
console.log(stu2); // { name: 'zhangsan', age: 18 }
在上面的代码中,我们使用 Object.assign 方法来对 stu 方法进行拷贝,并且可以看到修改拷贝后对象的值,并没有影响原来的对象,这仿佛实现了一个深拷贝。
然而,Object.assign 方法事实上是一个浅拷贝。
当对象的属性值对应的是一个对象时,该方法拷贝的是对象的属性的引用,而不是对象本身。
例如:
const stu = {name: 'xiejie',age: 18,stuInfo: {No: 1,score: 100}
}
const stu2 = Object.assign({}, stu)
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 90 } }
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }
3. ES6 扩展运算符
首先我们还是来回顾一下 ES6 扩展运算符的基本用法。
ES6 扩展运算符可以将数组表达式或者 string 在语法层面展开,还可以在构造字面量对象时,将对象表达式按 key-value 的方式展开。
例如:
var arr = [1, 2, 3];
var arr2 = [3, 5, 8, 1, ...arr]; // 展开数组
console.log(arr2); // [3, 5, 8, 1, 1, 2, 3]var stu = {name: 'xiejie',age: 18
}
var stu2 = { ...stu, score: 100 }; // 展开对象
console.log(stu2); // { name: 'xiejie', age: 18, score: 100 }
接下来我们来使用扩展运算符来实现对象的拷贝,如下:
const stu = {name: 'xiejie',age: 18
}
const stu2 = {...stu}
stu2.name = 'zhangsan';
console.log(stu); // { name: 'xiejie', age: 18 }
console.log(stu2); // { name: 'zhangsan', age: 18 }
但是和 Object.assign 方法一样,如果对象中某个属性对应的值为引用类型,那么直接拷贝的是引用地址。如下:
const stu = {name: 'xiejie',age: 18,stuInfo: {No: 1,score: 100}
}
const stu2 = {...stu}
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 90 } }
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }
4. 数组的 slice 和 concat 方法
在 javascript 中,数组也是一种对象,所以也会涉及到深浅拷贝的问题。
在 Array 中的 slice 和 concat 方法,不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。
例如:
// concat 拷贝数组
var arr1 = [1, true, 'Hello'];
var arr2 = arr1.concat();
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 1, true, 'Hello' ]arr2[0] = 2;
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 2, true, 'Hello' ]
// slice 拷贝数组
var arr1 = [1, true, 'Hello'];
var arr2 = arr1.slice();
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 1, true, 'Hello' ]arr2[0] = 2;
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 2, true, 'Hello' ]
但是,这两个方法仍然是浅拷贝。如果一旦涉及到数组里面的元素是引用类型,那么这两个方法是直接拷贝的引用地址。如下:
// concat 拷贝数组
var arr1 = [1, true, 'Hello', { name: 'xiejie', age: 18 }];
var arr2 = arr1.concat();
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]arr2[0] = 2;
arr2[3].age = 19;
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 19 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: 'xiejie', age: 19 } ]
// concat 拷贝数组
var arr1 = [1, true, 'Hello', { name: 'xiejie', age: 18 }];
var arr2 = arr1.slice();
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]arr2[0] = 2;
arr2[3].age = 19;
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 19 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: 'xiejie', age: 19 } ]
5. jQuery 中的 $.extend
在 jQuery 中,$.extend(deep,target,object1,objectN) 方法可以进行深浅拷贝。各参数说明如下:
- deep:如过设为 true 为深拷贝,默认是 false 浅拷贝
- target:要拷贝的目标对象
- object1:待拷贝到第一个对象的对象
- objectN:待拷贝到第N个对象的对象
来看一个具体的示例:
<body><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script><script>const obj = {name: 'wade',age: 37,friend: {name: 'james',age: 34}}const cloneObj = {};// deep 默认为 false 为浅拷贝$.extend(cloneObj, obj);obj.friend.name = 'rose';console.log(obj);console.log(cloneObj);</script>
</body>
效果:

深拷贝方法
说完了浅拷贝,接下来我们来看如何实现深拷贝。
总结一下,大致有如下的方式。
1. JSON.parse(JSON.stringify)
这是一个广为流传的深拷贝方式,用 JSON.stringify 将对象转成 JSON 字符串,再用 JSON.parse 方法把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
示例如下:
const stu = {name: 'xiejie',age: 18,stuInfo: {No: 1,score: 100}
}
const stu2 = JSON.parse(JSON.stringify(stu));
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 100 } }
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }
这种方式看似能够解决问题,但是这种方法也有一个缺点,那就是不能处理函数。
这是因为 JSON.stringify 方法是将一个 javascript 值(对象或者数组)转换为一个 JSON 字符串,而 JSON 字符串是不能够接受函数的。同样,正则对象也一样,在 JSON.parse 解析时会发生错误。
例如:
const stu = {name: 'xiejie',age: 18,stuInfo: {No: 1,score: 100,saySth: function () {console.log('我是一个学生');}}
}
const stu2 = JSON.parse(JSON.stringify(stu));
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 100, saySth: [Function: saySth] }}
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }
可以看到,在原对象中有方法,拷贝之后,新对象中没有方法了。
2. $.extend(deep,target,object1,objectN)
前面在介绍浅拷贝时提到了 jQuery 的这个方法,该方法既能实现浅拷贝,也能实现深拷贝。要实现深拷贝,只需要将第一个参数设置为 true 即可。例如:
<body><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script><script>const obj = {name: 'wade',age: 37,friend: {name: 'james',age: 34}}const cloneObj = {};// deep 设为 true 为深拷贝$.extend(true, cloneObj, obj);obj.friend.name = 'rose';console.log(obj);console.log(cloneObj);</script>
</body>
效果:

3. 手写递归方法
最终,还是只有靠我们自己手写递归方法来实现深拷贝。
示例如下:
function deepClone(target) {var result;// 判断是否是对象类型if (typeof target === 'object') {// 判断是否是数组类型if (Array.isArray(target)) {result = []; // 如果是数组,创建一个空数组// 遍历数组的键for (var i in target) {// 递归调用result.push(deepClone(target[i]))}} else if (target === null) {// 再判断是否是 null// 如果是,直接等于 nullresult = null;} else if (target.constructor === RegExp) {// 判断是否是正则对象// 如果是,直接赋值拷贝result = target;} else if (target.constructor === Date) {// 判断是否是日期对象// 如果是,直接赋值拷贝result = target;} else {// 则是对象// 创建一个空对象result = {};// 遍历该对象的每一个键for (var i in target) {// 递归调用result[i] = deepClone(target[i]);}}} else {// 表示不是对象类型,则是简单数据类型 直接赋值result = target;}// 返回结果return result;
}
在上面的代码中,我们封装了一个名为 deepClone 的方法,在该方法中,通过递归调用的形式来深度拷贝一个对象。
下面是 2 段测试代码:
// 测试1
const stu = {name: 'xiejie',age: 18,stuInfo: {No: 1,score: 100,saySth: function () {console.log('我是一个学生');}}
}
const stu2 = deepClone(stu)
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 100, saySth: [Function: saySth] }}
console.log(stu2); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 90, saySth: [Function: saySth] }}
// 测试2
var arr1 = [1, true, 'Hello', { name: 'xiejie', age: 18 }];
var arr2 = deepClone(arr1)
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]arr2[0] = 2;
arr2[3].age = 19;
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: 'xiejie', age: 19 } ]
真题解答
- 深拷贝和浅拷贝的区别?如何实现
参考答案:
浅拷贝:只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做浅拷贝(浅复制)
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝:在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响。
浅拷贝方法
- 直接赋值
- Object.assign 方法:可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。当拷贝的 object 只有一层的时候,是深拷贝,但是当拷贝的对象属性值又是一个引用时,换句话说有多层时,就是一个浅拷贝。
- ES6 扩展运算符,当 object 只有一层的时候,也是深拷贝。有多层时是浅拷贝。
- Array.prototype.concat 方法
- Array.prototype.slice 方法
- jQuery 中的 . e x t e n d ∗ :在 ∗ j Q u e r y ∗ 中, ∗ .extend*:在 *jQuery* 中,* .extend∗:在∗jQuery∗中,∗.extend(deep,target,object1,objectN) 方法可以进行深浅拷贝。deep 如过设为 true 为深拷贝,默认是 false 浅拷贝。
深拷贝方法
- $.extend(deep,target,object1,objectN),将 deep 设置为 true
- JSON.parse(JSON.stringify):用 JSON.stringify 将对象转成 JSON 字符串,再用 JSON.parse 方法把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。这种方法虽然可以实现数组或对象深拷贝,但不能处理函数。
- 手写递归
示例代码如下:
function deepCopy(oldObj, newobj) {for (var key in oldObj) {var item = oldObj[key];// 判断是否是对象if (item instanceof Object) {if (item instanceof Function) {newobj[key] = oldObj[key];} else {newobj[key] = {}; //定义一个空的对象来接收拷贝的内容deepCopy(item, newobj[key]); //递归调用}// 判断是否是数组} else if (item instanceof Array) {newobj[key] = []; //定义一个空的数组来接收拷贝的内容deepCopy(item, newobj[key]); //递归调用} else {newobj[key] = oldObj[key];}} }
-EOF-
相关文章:

深浅拷贝详解
深浅拷贝 经典真题 深拷贝和浅拷贝的区别?如何实现 深拷贝和浅拷贝概念 首先,我们需要明确深拷贝和浅拷贝的概念。 浅拷贝:只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷…...
@Scheduled 定时任务
Scheduled(cron"30 * * * * ?") 1.cron表达式格式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)} 2.cron表达式各占位符解释: {秒数}{分钟} > 允许值范围: 0~59 ,不允许为空值,若值不合法,调度器将…...

丙烯酸共聚聚氯乙烯树脂
声明 本文是学习GB-T 42790-2023 丙烯酸共聚聚氯乙烯树脂. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件规定了丙烯酸共聚聚氯乙烯树脂的外观、物化性能等技术要求,描述了相应的采样、试验方 法、检验规则、标志、包装、…...

Navicat导入Excel数据顺序变了
项目场景: Navicat导入Excel数据 问题描述 从Excel表格中导入数据到数据库中。但是,在导入的过程中,我们常会发现数据顺序出现了问题,导致数据错位,给数据的处理带来了极大的麻烦。 原因分析: 这个问题的…...
uni-app的生命周期
uni-app的生命周期包括应用生命周期和页面生命周期。 应用生命周期涵盖了整个uni-app应用的启动、运行和销毁过程,主要包括以下几个生命周期函数: onLaunch:应用初始化时触发,只触发一次。onShow:应用启动或从后台进…...

Vulnhub实战-DC9
前言 本次的实验靶场是Vulnhub上面的DC-9,其中的渗透测试过程比较多,最终的目的是要找到其中的flag。 一、信息收集 对目标网络进行扫描 arp-scan -l 对目标进行端口扫描 nmap -sC -sV -oA dc-9 192.168.1.131 扫描出目标开放了22和80两个端口&a…...

软件设计模式系列之七——原型模式
1 模式的定义 原型模式(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制现有对象来创建新对象,而不是使用构造函数。原型模式将对象的创建委托给原型对象,通过克隆(复制)来生成新…...

PMP考试注意事项有哪些?
1. PMI明确规定:不允许考生使用自带文具,包括自带的笔、削笔刀、橡皮、笔袋、计算器和草稿纸等。 2. 本次考试考场内为每位考生配备2B铅笔、橡皮、计算器(若有需要)和草稿纸。如文具有缺损或考试过程中如需更换铅芯等,请向监考老师举手示意。…...
chartgpt+midjourney
chatGPT程序化生成故事 英文版脚本步骤 步骤一:在chatgpt中输入以下脚本,,标红为可变的文字,输入你想要的,目前是科幻,即科幻故事,你可以改为 fairy-tale,则写的是童话故事&#x…...

【SpringMVC】自定义注解
【SpringMVC】自定义注解 前言1. 什么是注解?2. 注解的用处3. 注解的原理1.1. Override1.2. SuppressWarnings 2. JDK元注解2.1. Retention2.2. Target2.3. Inherited2.4. Documented 3. 自定义注解3.1. 自定义注解的分类注解类 结语 自定义注解及其应用 前言 在J…...

【李沐深度学习笔记】数据操作实现
课程地址 数据操作实现p2 数据操作 首先导入PyTorch包(import torch),虽然叫PyTorch,但实际上要导入torch。 import torch张量 张量表示的是一个数值组成的数组,这个数组可以有很多个维度。 # 生成0-11的顺序序列构成的一维…...

【深度学习-注意力机制attention 在seq2seq中应用】
注意力机制 为什么需要注意力机制attention机制的架构总体设计一、attention本身实现评分函数 attention在网络模型的应用-Bahdanau 注意力加性注意力代码实现 为什么需要注意力机制 这是一个普通的seq2seq结构,用以实现机器对话,Encoder需要把一个输入的…...

详解混合类型文件(Polyglot文件)的应用生成与检测
1. 引入 混合类型文件(Polyglot文件),是指一个文件,既可以是合法的A类型,也可以是合法的B类型。 比如参考3中的文件,是一个html文件,可以用浏览器正常打开;它也是一个一个.jar文件&…...
QT之QTableView的简介
QT之QTableView的简介 QTableView 是 Qt 框架中的一个类,用于显示和编辑表格数据。它提供了一个灵活的模型/视图架构,允许用户以不同的方式显示和编辑数据。 以下是 QTableView 的一些常用函数及其用法: 1)QTableView(QWidget *pa…...

学习记忆——宫殿篇——记忆宫殿——记忆桩——知识讲解
类比 假设这些桩子好比不同的交通工具,每一种交通工具都可以助我们到达目的地,那举现在就根据你的时间以及现实情况,选择最合适自己的交通工具即可,重点在于你要熟悉每种交通工具的用途不区别。桩子也是如此,把所有的桩…...
Python lambda匿名函数
视频版教程 Python3零基础7天入门实战视频教程 前面我们所学的函数定义,都是有函数名的。 我们现在学的lambda函数是没有名称的,也就是匿名函数。 我们在只需要一次性使用的函数的时候,就可以用lambda匿名函数,简单方便快捷。 …...
成绩统计(蓝桥杯)
成绩统计 题目描述 小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。 如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。 请计算及格率和优秀率,用百分数…...

ETL与ELT理解
ETL ETL( Extract-Transform-Load),用来描述将数据从来源端经过抽取(Extract)、转换(Transform)、加载(Load)至目的端的过程。ETL模式适用于小数据量集。如果在转换过程…...

IntelliJ IDEA 2023 年下载、安装教程、好用插件推荐
文章目录 下载与安装IDEA常用插件推荐Alibaba Java Coding Guidelines(阿里巴巴Java开发规约)Key Promoter X(IDEA快捷键提示)Translation(翻译插件)Save Actions(优化保存插件)Codo…...

下载HTMLTestRunner并修改
目录 一. 下载HTMLTestRunner 二. 修改HTMLTestRunner 1. 修改内容 2. 修改原因 一. 下载HTMLTestRunner 下载报告模板地址:http://tungwaiyip.info/software/HTMLTestRunner.html 下载模块: 二. 修改HTMLTestRunner 将修改后的模块放到python安装目录下的..…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...