Javascript数据类型和类型转换
Javascript数据类型和类型转换
在JavaScript中,理解数据类型,如何区分它们,以及它们如何被转换是至关重要的。在这篇文章中,我们将探讨这些主题,以帮助巩固你的JavaScript基础。
基础数据类型和引用数据类型
当涉及JavaScript的数据类型时,我们可以将其分为两类:基本数据类型和引用数据类型。
1、基本数据类型(Primitive Types):
-
数字(Number):表示数值,可以包含整数和浮点数。例如:
let age = 25;
-
字符串(String):表示文本数据,由一串字符组成。可以使用单引号或双引号包裹。例如:
let name = 'John';
-
布尔(Boolean):表示逻辑值,只有两个可能的值:
true
(真)和false
(假)。例如:let isStudent = true;
-
空值(Null):表示空值或无值。它是一个特殊的关键字
null
。例如:let myVariable = null;
-
未定义(Undefined):表示变量声明但未赋值的值。它是一个特殊的关键字
undefined
。例如:let myVariable;
-
未定义(Undefined):表示变量声明但未赋值的值。它是一个特殊的关键字
undefined
。例如:let myVariable;
2、引用数据类型(Reference Types):
对象(Object):表示复杂的数据结构,可以包含多个键值对。对象可以通过大括号{}
创建,或者通过构造函数创建。例如:
let person = {name: 'John',age: 25,city: 'New York'
};
数组(Array):表示有序的数据集合,可以包含任意类型的数据。数组可以通过方括号[]
创建。例如:
let numbers = [1, 2, 3, 4, 5];
函数(Function):是一段可执行的代码块,可以接收参数并返回值。函数可以作为变量、参数传递、存储在对象属性中等。例如:
function greet(name) {console.log('Hello, ' + name + '!');
}
基本数据类型在JavaScript中是按值传递的,而引用数据类型则是按引用传递的。这意味着基本数据类型的值在传递过程中是复制的,而引用数据类型的值在传递过程中是共享的。
了解这些基本数据类型和引用数据类型,为后续讲解类型转换提供了基本的背景知识。它们在JavaScript中的不同行为和用法对于理解类型转换的概念和机制非常重要。
使用typeof操作符
在JavaScript中,我们可以使用typeof
操作符来获取一个值的数据类型。下面是一些例子:
console.log(typeof undefined); // 'undefined'
console.log(typeof true); // 'boolean'
console.log(typeof 78); // 'number'
console.log(typeof 'hey'); // 'string'
console.log(typeof Symbol()); // 'symbol'
console.log(typeof BigInt(1)); // 'bigint'
console.log(typeof new String('abc')); // 'object'
console.log(typeof null); // 'object'
console.log(typeof function(){}); // 'function'
console.log(typeof {name: 'Jack'}); // 'object'
注意,typeof返回的是值的类型,而不是变量的类型。因为在JavaScript中,变量本身并没有类型,它们可以持有任何类型的值。
对大多数对象使用typeof时,返回的结果是'object',对于函数则返回'function'。特别的,对null使用typeof返回的也是'object',这是一个历史遗留的bug,我们无法改正。所以,如果我们需要检查一个值是否为null,我们可以使用以下方式:
var a = null;
console.log(!a && typeof a === "object"); // true
包装类型
在JavaScript中,基本数据类型有对应的包装对象,这样我们就可以在基本数据类型上调用方法了。例如,字符串有对应的String
包装对象,我们就可以在字符串上调用String
对象的方法:
let s = 'Hello, world!';
console.log(s.length); // 13
这里,length是String对象的一个属性,我们可以在字符串s上访问它。这是如何做到的呢?当我们在一个字符串上调用一个方法或者访问一个属性时,JavaScript会将字符串自动转换为一个临时的String对象,然后在这个临时对象上调用方法或者访问属性。完成后,临时对象就会被销毁。
其他的基本数据类型,如Number,Boolean,也有对应的包装对象,操作方式类似。
隐式类型转换
在JavaScript中,隐式类型转换是指在特定的上下文中,JavaScript自动将一个数据类型转换为另一个数据类型,而无需显式地编写转换代码。
1. 数字转字符串:
let num = 10;
let str = num + ''; // 将数字转换为字符串
console.log(str); // 输出: "10"
通过将数字与一个空字符串相加,JavaScript会将数字隐式转换为字符串。
2. 字符串转数字:
let str = '20';
let num = +str; // 将字符串转换为数字
console.log(num); // 输出: 20
通过使用一元加号操作符(+)对字符串进行操作,JavaScript会将字符串隐式转换为数字。
3. 布尔值转数字:
let bool = true;
let num = +bool; // 将布尔值转换为数字
console.log(num); // 输出: 1
通过使用一元加号操作符(+)对布尔值进行操作,JavaScript会将布尔值隐式转换为数字,true
转换为1,false
转换为0。
4. 字符串转布尔值:
let str = 'true';
let bool = !!str; // 将字符串转换为布尔值
console.log(bool); // 输出: true
通过使用两个逻辑非操作符(!!)对字符串进行操作,JavaScript会将字符串隐式转换为布尔值,非空字符串转换为true,空字符串转换为false。
需要注意的是,隐式类型转换在某些情况下可能会导致意外的结果。因此,在进行类型转换时,特别是涉及不同的数据类型之间的运算时,要注意确保结果符合预期。
理解隐式类型转换的规则和机制可以帮助我们更好地理解JavaScript代码中的行为,并在需要时正确地处理数据类型转换。
5. 对象的隐式转换
在JavaScript中,对象在进行隐式类型转换时会根据一定的规则进行处理。对象的隐式类型转换通常涉及将对象转换为字符串或将对象转换为数字。
5.1、对象转换为字符串:
当一个对象需要被隐式转换为字符串时,JavaScript会尝试调用对象的toString()
方法。toString()
方法是一个内置方法,它返回表示对象的字符串形式。
let obj = { name: "John", age: 25 };let str = obj.toString();console.log(str); // 输出: "[object Object]"
在上述例子中,对象obj会被隐式转换为字符串形式,调用了toString()方法并返回了"[object Object]"。
需要注意的是,toString()方法的默认实现返回"[object Object]",这对于大多数对象来说并不是非常有用。因此,可以通过重写对象的toString()方法来自定义对象转换为字符串的行为。
let person = {name: "John",age: 25,toString() {return this.name + " - " + this.age;}
};
let str = person.toString();
console.log(str); // 输出: "John - 25"
我们重写了person
对象的toString()
方法,使其返回自定义的字符串形式。
5.2、对象转换为数字:
在JavaScript中,当一个对象需要被隐式转换为数字时,会首先尝试调用对象的valueOf()方法,如果该方法返回的不是原始值(例如数字),则会接着尝试调用对象的toString()方法,将返回值转换为数字
let obj = { value: 42 };let num = obj.valueOf();console.log(num); // 输出: { value: 42 }
需要注意的是,与日期对象的valueOf()
方法不同,大多数对象的默认valueOf()
方法的行为通常并不有用。因此,可以通过重写对象的valueOf()
方法来自定义对象转换为数字的行为。
let counter = {value: 0,valueOf() {return this.value++;}
};let num = counter.valueOf();console.log(num); // 输出: 0console.log(counter.value); // 输出: 1
我们重写了counter
对象的valueOf()
方法,使其每次调用时返回一个递增的值。
需要注意的是,对象的隐式类型转换的行为和结果可能会因对象的类型、实现方式以及具体的上下文而有所不同。在编写代码时,建议根据实际需求和预期结果来处理对象的隐式类型转换,并确保理解和掌握对象的toString()
和valueOf()
方法的使用。
显式类型转换
在JavaScript中,我们可以使用一些内置函数和操作符来进行显式类型转换,以将一个值转换为特定的数据类型。下面是一些常用的类型转换函数和操作符以及它们的用法和注意事项:
1、String() 函数:用于将一个值转换为字符串类型。
let num = 10;let str = String(num); // 将数字转换为字符串console.log(str); // 输出: "10"
需要注意的是,使用String()函数进行转换时,对于 null 和 undefined 值会分别得到 “null” 和 “undefined” 字符串。
2、Number() 函数:用于将一个值转换为数字类型。
let str = "20";let num = Number(str); // 将字符串转换为数字console.log(num); // 输出: 20
需要注意的是,使用Number()函数进行转换时,如果传入的字符串无法解析为有效的数字,将返回 NaN(Not a Number)。
3、Boolean() 函数:用于将一个值转换为布尔类型。
let num = 0;let bool = Boolean(num); // 将数字转换为布尔值console.log(bool); // 输出: false
需要注意的是,使用Boolean()函数进行转换时,对于 0、-0、null、undefined、NaN 和空字符串会返回 false,其他值都会返回 true。
4、parseInt() 和 parseFloat() 函数:用于将字符串转换为整数和浮点数类型。
let str = "123";let num = parseInt(str); // 将字符串转换为整数console.log(num); // 输出: 123let floatStr = "3.14";let floatNum = parseFloat(floatStr); // 将字符串转换为浮点数console.log(floatNum); // 输出: 3.14
需要注意的是,使用 parseInt() 和 parseFloat() 函数进行转换时,它们会尝试解析字符串的开头部分,直到遇到非数字字符为止。
除了上述函数,还有一些常用的操作符也可以进行显式类型转换:
- 加号操作符(+):用于将值转换为数字类型。
-
let str = "20";let num = +str; // 将字符串转换为数字console.log(num); // 输出: 20
- 双重取反操作符(!!):用于将值转换为布尔类型。
-
let num = 0;let bool = !!num; // 将数字转换为布尔值console.log(bool); // 输出: false
在进行显式类型转换时,需要注意以下几点:
- 了解转换函数和操作符的行为和规则,以避免出现意外的结果。
- 特别注意在将字符串转换为数字时,确保字符串能够正确解析为有效的数字,以避免得到 NaN。
- 注意处理 null 和 undefined 值时的类型转换结果。
- 在类型转换场景中,根据具体需求选择合适的函数或操作符。
通过显式类型转换,我们可以将值从一个数据类型转换为另一个数据类型,以满足具体的需求和逻辑。
类型转换规则
了解类型转换的规则和注意事项是非常重要的,可以帮助我们避免出现意外的结果和错误的行为。下面是一些类型转换的规则和需要注意的情况:
1、类型转换的优先级:在JavaScript中,类型转换有一定的优先级。从高到低的优先级顺序是:
布尔值 -> 数字 -> 字符串
这意味着在进行混合类型的操作时,JavaScript会首先尝试将值转换为布尔值,然后是数字,最后是字符串。
2、字符串拼接优先:在涉及字符串和其他数据类型的操作中,字符串拼接的优先级最高。这意味着如果一个操作符是字符串拼接操作符(+),那么其他操作数将被隐式转换为字符串。
let num = 10;let str = "The number is: " + num;console.log(str); // 输出: "The number is: 10"
数字num
会被隐式转换为字符串,然后与其他字符串进行拼接。
3、NaN(Not a Number):当涉及无法进行有效数值计算的情况时,JavaScript会返回NaN。NaN是一个特殊的数字值,表示不是一个有效的数字。
let result = 10 / "hello";console.log(result); // 输出: NaN
字符串"hello"无法被解析为有效的数字,所以计算结果为NaN。
4、null和undefined的类型转换:null和undefined在进行类型转换时有一些特殊规则:
- null在进行数字转换时会被转换为0,而在进行字符串转换时会被转换为"null"。
- undefined在进行数字转换时会被转换为NaN,而在进行字符串转换时会被转换为"undefined"。
-
let num = Number(null);console.log(num); // 输出: 0let str = String(undefined);console.log(str); // 输出: "undefined"
null在数字转换时被转换为0,undefined在字符串转换时被转换为"undefined"。
5、注意一元加号操作符(+)的行为:一元加号操作符可以用于将值转换为数字类型,但需要注意一些情况。当应用于字符串时,一元加号操作符会尝试将字符串解析为数字。
let str = "123";let num = +str;console.log(num); // 输出: 123let invalidStr = "hello";let invalidNum = +invalidStr;console.log(invalidNum); // 输出: NaN
有效的数字字符串可以成功转换为数字,而无法解析为数字的字符串会转换为NaN。
了解这些规则和注意事项可以帮助我们更好地理解类型转换的行为,并在编写代码时避免潜在的错误和意外结果。同时,在进行类型转换时,要根据具体的需求选择合适的方法和操作符,并进行适当的错误处理和边界检查。
最佳实践
在JavaScript中,了解一些类型转换的最佳实践和常见应用场景,以帮助我们编写更安全、清晰和高效的代码:
1、避免意外的类型转换:隐式类型转换可能导致意外的结果和错误的行为。为了避免这种情况,可以遵循以下实践:
- 显式地使用适当的类型转换函数或操作符,明确指定期望的转换结果。
- 在涉及类型转换的操作中,添加适当的错误处理机制,以防止无效的转换。
2、类型安全的比较:在条件语句中,确保进行类型安全的比较,避免因类型转换而导致的问题。使用恰当的比较操作符(如===
和!==
)可以同时比较值和类型,确保比较的准确性。
let num = "10";if (num === 10) {// 正确的比较方式,值和类型都匹配console.log("The number is 10.");
} else {console.log("The number is not 10.");
}
使用===
进行比较可以避免字符串与数字的隐式转换,确保比较的准确性。
3、使用适当的类型转换技巧:在某些情况下,可以使用类型转换来解决问题或优化代码逻辑。
- 将字符串转换为数字或反之:使用Number()函数或一元加号操作符(+)进行转换。
- 将字符串转换为数组:使用split()函数将字符串拆分为数组。
- 将对象转换为字符串:使用JSON.stringify()函数将对象转换为字符串表示。
- 将数字转换为字符串并添加特定格式:使用字符串模板或字符串拼接操作符(+)。
4、考虑性能和可读性:尽管类型转换是一种强大的工具,但过度使用或滥用可能会影响代码的性能和可读性。在进行类型转换时,要权衡利弊,并确保代码易于理解和维护。
总之,掌握类型转换的最佳实践可以帮助我们编写更健壮和高效的代码。遵循类型安全的比较、避免意外的类型转换、选择适当的类型转换技巧,并在性能和可读性之间找到平衡,都是编写优质JavaScript代码的重要因素。
参考资料
-
MDN Web Docs - Type Conversion: MDN Web Docs中关于JavaScript中类型转换的官方文档,提供了关于隐式类型转换和显式类型转换的详细解释和示例。
-
MDN Web Docs - toString(): MDN Web Docs中关于
toString()
方法的官方文档,提供了有关对象的toString()
方法的详细解释和用法示例。 -
MDN Web Docs - valueOf(): MDN Web Docs中关于
valueOf()
方法的官方文档,提供了有关对象的valueOf()
方法的详细解释和用法示例。
相关文章:
Javascript数据类型和类型转换
Javascript数据类型和类型转换 在JavaScript中,理解数据类型,如何区分它们,以及它们如何被转换是至关重要的。在这篇文章中,我们将探讨这些主题,以帮助巩固你的JavaScript基础。 基础数据类型和引用数据类型 当涉及…...

冲刺十五届蓝桥杯P0005单词分析
文章目录 题目分析代码 题目 单词分析 分析 统计字符串中字母出现的次数,可以采用哈希表,代码采用的是数组来存储字符,将字符-97,得到对应的数组下标,将对应下标的数组;找到数组元素最大的下标ÿ…...

php获取10年内的年份并加入下拉列表
要实现的效果 在html中内嵌php循环将数组中的年份加入下拉列表 <div class="form-group"><label>年份:</label><div class="input-group"><div class="input-group-prepend"><span class="input-group-te…...

2020年亚太杯APMCM数学建模大赛B题美国总统的经济影响分析求解全过程文档及程序
2020年亚太杯APMCM数学建模大赛 B题 美国总统的经济影响分析 原题再现: 美国总统选举每四年举行一次。 2020年是美国总统大选年,共和党候选人唐纳德特朗普和民主党对手乔拜登竞选总统。 甲乙双方候选人在金融贸易,经济金融治理,…...

保护隐私就是在保护自己!如何在Android上更改应用程序权限
如果你关心隐私,知道如何在Android上更改应用程序权限将成为一项非常重要的技能。即使是最好的安卓应用程序也可以对手机的功能和数据进行广泛的访问,因此准确控制它们的使用范围会有所帮助。 一旦你在手机上加载了应用程序,你可能会注意到它…...

Linux/Ubuntu 安装 Java运行环境
linux下安装Java运行环境 1、下载安装包 .tar.gz 先在官网下载 JDK 点击这里 在这里要选择对应的 JDK 版本,一般我们目前选择JDK8 点击这里 2、在 /usr/local/ 目录下创建Java文件夹 cd /usr/local/ mkdir java3、将下载的文件通过FTP程序上传到刚刚创建的Java文…...
vue2 中activated和deactivated是详细解说
activated 和 deactivated 是 Vue.js 中的生命周期钩子函数,主要用于处理组件在 keep-alive 缓存中进入和离开时的行为。 这些钩子函数通常用于在组件进入缓存时执行特定的操作,以及在组件离开缓存时执行清理操作。 下面是关于这两个钩子函数的用例和示例…...

C# GFPGAN 图像(人脸面部)修复
效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms;namespace 图像修复 {pu…...
ruoyi项目登录验证变更
背景:我用的是ruoyi-vue3.8.6版本,因公司需要使用window的域用户进行登录验证,因此原有的ruoyi登录验证方法就得替换掉 1. 首先登录系统添加一些域账号,以确保登录方式更改后,能在sys_user中找到该账号,因…...
maven依赖冲突以及解决方法
什么是依赖冲突 依赖冲突是指项目依赖的某一个jar包,有多个不同的版本,因而造成类包版本冲突 依赖冲突的原因 依赖冲突很经常是类包之间的间接依赖引起的。每个显式声明的类包都会依赖于一些其它的隐式类包,这些隐式的类包会被maven间接引…...
K8S常用的一些命令及工具
已json格式输出 [rootk8master1 ~]# yum install epel-release [rootk8master1 ~]# yum -y install jq [rootk8master1 ~]# kubectl get --raw /api/v1/namespaces/dev | jq {"kind": "Namespace","apiVersion": "v1","metadata…...
Atlas 200I DK目标检测与追踪技术记录
数据集 数据集采用MOT系列,MOT是多目标追踪常用数据集,MOT数据集对数据集进行了分帧,如要获得视频,需要先利用opencv里的cv2.VideoWriter模块便利图片文件夹,具体代码如下: import os import cv2img_path…...
php如何在header增加key,sign,timestamp?怎么鉴权?
在PHP中,您可以通过在HTTP请求的Header中增加Key、Sign和Timestamp等信息来进行安全性鉴权。 以下是一种基本的思路和示例,用于说明如何实现这种鉴权机制: 生成Key和Sign: 服务端和客户端之间共享一个密钥(Key&#x…...
从代码入手理解卡尔曼滤波器的原理之使用Eigen实现二维卡尔曼滤波器(七)
当然可以。现在,给定了矩阵和向量的具体定义,我们可以更详细地解释这些变量的意义,并确定卡尔曼滤波器的维度。 F (状态转移矩阵): F 是一个2x2的矩阵,给定为:1 0 0 1这意味着系统的状态从时刻t到t+1没有实质变化,即每个状态都保持不变。 H (观测矩阵): H 也是一个2x2的矩…...

文件的操作
前言:哈喽小伙伴们好久不见,国庆假期已经结束,接下来我们还是要马不停蹄的投入到学习当中,只有尽快调整状态回归学习,才能弯道超车。 今天我们一起来学习C语言——文件操作。 本篇文章讲到的所有函数均需要头文件#inc…...

left join时筛选条件对查询结果的
-- 创建表 CREATE TABLE table1 (id int(11) NOT NULL AUTO_INCREMENT,card_num varchar(60) DEFAULT NULL,customer_id varchar(60) DEFAULT NULL,PRIMARY KEY (id) ) ENGINE InnoDBAUTO_INCREMENT 12DEFAULT CHARSET utf8mb4 COMMENT 测试表1;-- 创建表 CREAT…...

CVE-2020-9483 apache skywalking SQL注入漏洞
漏洞概述 当使用H2 / MySQL / TiDB作为Apache SkyWalking存储时,通过GraphQL协议查询元数据时,存在SQL注入漏洞,该漏洞允许访问未指定的数据。 Apache SkyWalking 6.0.0到6.6.0、7.0.0 H2 / MySQL / TiDB存储实现不使用适当的方法来设置SQL参…...

PaddleX解决分类、检测两大场景问题?实战精讲教程来了!
AI技术加速数字化进程,从制造、交通、能源等基础行业,到医疗、城市、零售、家居等与人们日常生活息息相关的行业,AI技术推动了数字化变革,也不断赋能于千行百业,但产业落地实践中依然面临着数据、算法等诸多困难。为了…...
Hive用户中文使用手册系列(二)
命令和 CLI 语言手册命令 命令是 non-SQL statements,例如设置 property 或添加资源。它们可以在 HiveQL 脚本中使用,也可以直接在CLI或Beeline中使用。 命令描述退出使用 quit 或 exit 退出交互式 shell。重启将 configuration 重置为默认值(从 Hive…...

2023年中国清净剂行业需求现状及前景分析[图]
清净剂用于中和由于燃烧和润滑油氧化产生的酸性物质,并清除颗粒和污物。这类杂质在油中的溶解度有限,因此,清净剂可以最大程度减少沉积物的生成,降低污染,提高环保排放标准。成熟产品有磺酸盐、硫化烷基酚盐、烷基水杨…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...