• 01 【基础语法与基本数据类型】


    1.基础语法&基本数据类型

    语言功能
    结构层HTML搭建结构、放置部件、描述语义
    样式层CSS美化网页、实现布局
    行为层JavaScript实现交互效果、数据收发、表单验证等

    1997 年,欧洲计算机制造商协会(ECMA)颁布了 JavaScript 的标准,命名为 ECMAScript。

    ECMAScript 简称 ES,JavaScript 简称 JS。

    • JavaScript 实现了 ECMAScript

    • ECMAScript 规范了 JavaScript

    JavaScript 的语言风格和特性

    • 类 C 语言风格,容易上手
    • 弱类型(动态类型),简单易学
    • 丰富的功能,无敌的生态,强大的性能

    1.1 基本使用

    1.1.1 输出语句

    alert("要输出的内容");
    
    • 1

    该语句会在浏览器窗口中弹出一个警告框

    【功能】

    在浏览器(JavaScript 引擎 例如:Chrome V8)解析到 JS 文件中的 alert() 语句时,便会中断 JS 脚本的执行,同时弹出警告框,直到用户单击确定后,才继续执行后续的 JS 脚本。

    document.write("要输出的内容");
    
    • 1

    该内容将会被写到body标签中,并在页面中显示

    console.log("要输出的内容");
    
    • 1

    console:控制台

    log:记录、日志

    • console 是 JS 的内置对象
    • 通过对象 “打点” 可以调用其内部的 log 方法(所谓 “方法” 就是对象能够调用的函数)

    F12 打开浏览器调试面板,点击 Console 控制台菜单。

    【功能】

    在浏览器(JavaScript 引擎 例如:Chrome V8)解析到 JS 文件中的 console.log() 语句时,会直接在浏览器控制台输出语句,并自动继续执行后续的 JS 脚本。

    输入语句

    • 使用 prompt() 函数弹出浏览器输入框

    • 由于 prompt() 函数输入的任何值都将默认为字符串

    1.1.2 编写位置

    • 中的 引入

    JavaScript 不能脱离 HTML 网页运行!

    (当然,今后学习 Node.js 后,JavaScript 可以独立成为一个运行平台)

    1.可以编写到标签的指定属性中

    <button onclick="alert('hello');">我是按钮button>  
    <a href="javascript:alert('aaa');">超链接a>
    
    • 1
    • 2

    2.可以编写到script标签中

    <body>
        
        
    
        
        
        <script>
            // 弹窗输出一句话
            // 每一句 JS 代码以分号结尾!
            alert("你好,JavaScript!");
        script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.可以将代码编写到外部的js文件中,然后通过标签将其引入

    script标签一旦用于引入外部文件了,就不能在编写代码了,即使编写了浏览器也会忽略 ,如果需要则可以在创建一个新的script标签用于编写内部代码

    <script type="text/javascript" src="文件路径">script>
    
    • 1

    1.1.3 基本语法

    js函数声明不需要;分号,但是赋值语句要加;分号

    function functionName(arg0,arg1,arg2){  
    //函数声明  
    }  
    var functionName=function(arg0,arg1,arg2){  
    //函数表达式  
    };(注意分号)  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注释

    单行注释

    //注释内容  
    
    • 1

    多行注释

    /*  
    注释内容  
    */  
    
    • 1
    • 2
    • 3

    JS严格区分大小写

    JS中每条语句以分号(;)结尾如果不写分号,浏览器会自动添加,但是会消耗一些系统资源, 而且有些时候,浏览器会加错分号,所以在开发中分号必须写

    JS中会自动忽略多个空格和换行,所以我们可以利用空格和换行对代码进行格式化。

    1.1.4 字面量(值)和变量

    字面量

    字面量实际上就是一些固定的值,比如 1 2 3 4 true false null NaN “hello”
    字面量都是不可以改变的。

    由于字面量不是很方便使用,所以在JS中很少直接使用字面量

    变量

    变量可以用来保存字面量,并且可以保存任意的字面量

    一般都是通过变量来使用字面量,而不直接使用字面量,而且也可以通过变量来对字面量进行一个描述

    声明变量

    使用var关键字来声明一个变量

    var a;  
    
    • 1

    为变量赋值

    a = 1; 
    
    • 1

    声明和赋值同时进行

    var a = 456;   
    
    • 1

    1.1.5 标识符

    在JS中所有的可以自主命名的内容,都可以认为是一个标识符,
    是标识符就应该遵守标识符的规范。

    函数、类名、对象的属性等也都要遵守这个标识符的命名规则。

    1.1.6 推荐的变量命名风格

    • 小驼峰命名法:mathTestScore (吐血推荐)
    • C 风格变量命名法:math_test_score

    补充:

    • 驼峰命名法:Java、JavaScript
    • 下划线命名法:C、C++、Python、Golang、SQL

    1.1.7 变量的默认值

    • 一个变量只定义,但没有赋初值,默认值是 undefined(未阐明)
    • 一个变量只有被 var 定义,并赋初值之后,才算正式初始化完成
    var a;	// 只定义但没有赋初值
    console.log(a);	// undefined
    a = 24;
    console.log(a);	// 24
    
    • 1
    • 2
    • 3
    • 4

    1.1.8 变量的常见错误

    • 不用 var 定义,而直接将值赋予它,虽然不引发报错,但会产生作用域问题。

    请一律加上 var

    a = 24; // 未使用 var 定义的变量默认为全局变量!成为 window 对象的属性。
    console.log(a);	// 24
    console.log(window.a);	// 24
    console.log(window.a === a);	// true
    
    • 1
    • 2
    • 3
    • 4

    关于作用域的问题,后期课程会介绍。

    • 尝试使用一个既没有被 var 定义过,也没有赋过值的变量,就会产生引用错误。
    console.log(c);
    // index.js:1 Uncaught ReferenceError: c is not defined at index.js:1
    
    • 1
    • 2

    使用 strict 严格模式

    JavaScript 在设计之初,为了方便初学者学习,并不强制要求用 var 申明变量。这个设计错误带来了严重的后果:如果一个变量没有通过 var 申明就被使用,那么该变量就自动被申明为全局变量:

    i = 10; // i 现在是全局变量
    
    • 1

    在同一个 HTML 页面的不同的 JavaScript 文件中,如果都不用 var 申明,恰好都使用了变量 i,将造成变量 i 互相影响,产生难以调试的错误结果。

    使用 var 申明的变量则不是全局变量,它的范围被限制在该变量被申明的 JS 文件或函数体内(函数的概念将稍后讲解),同名变量在不同的函数体内互不冲突。

    为了修补 JavaScript 这一严重设计缺陷,ECMA 在后续规范中推出了 strict 模式,在 strict 模式下运行的 JavaScript 代码,强制通过 var 申明变量,未使用 var 申明变量就使用的,将导致运行错误。

    启用 strict 模式的方法是在 JavaScript 代码的第一行写上:

    "use strict";
    
    • 1

    这是一个字符串,不支持 strict 模式的浏览器会把它当做一个字符串语句执行,支持 strict 模式的浏览器将开启 strict 模式运行 JavaScript。

    "use strict";
    abc = "Hello, world";
    console.log(abc);
    // 如果浏览器支持 strict 模式,
    // 下面的代码将报 ReferenceError 错误:Uncaught ReferenceError: abc is not defined
    
    • 1
    • 2
    • 3
    • 4
    • 5

    不用 var 申明的变量会被视为全局变量,为了避免这一缺陷,所有的 JavaScript 代码都推荐使用 strict 模式。

    提示:"use strict"语句可以放在 JS 代码的任意一行上,并且它只对它所在作用域下方的代码起作用。

    1.1.9 等号表示赋值

    var a = 10;
    a = a + 1;
    console.log(a);	// 11
    a = a - 1;
    console.log(a);	// 10
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.1.10 同时声明多个变量

    var a = 0, b = 1, c = 2;	// 建议每行只声明一个变量
    
    • 1

    1.1.11 变量声明提升

    • 变量声明的提升:可以提前使用一个稍后才声明的变量,而不会引发异常
    • 在执行所有代码前,JS 有预解析阶段,会预读所有变量的声明(不会提升赋值,只会提升定义)
    // 变量声明提升的只是定义,不提升赋值!!!
    // 先使用变量
    console.log(a);	// undefined
    var a = 10;
    // 后定义变量
    console.log(a);	// 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    实际的情况相当于:

    var a;
    console.log(a); // undefined
    a = 10;
    console.log(a); // 10
    
    • 1
    • 2
    • 3
    • 4

    【注意事项】

    • 变量声明提升是 JS 的独有特性!
    • 在实际开发中,不要刻意使用变量提升的特性,一定要先定义再使用!
    • 严格模式对变量提升没有检测作用(严格模式也搞不定变量提升这个老赖)!

    1.1.12 学会处理报错

    JS 一但发生语句错误,那么后续的语句也就不执行了!

    浏览器控制台会检测错误的类型及行号(行号不一定正确,但可以确定范围)

    现代 IDE 一般具备智能自动检查功能,最智能的 JavaScript IDE:WebStorm

    • Uncaught SyntaxError: Invalid or unexpected token

    未捕获的语法错误:不合法或错误的符号。

    (中文符号错误、……)

    • Uncaught ReferenceError: jerry is not defined

    未捕获的引用错误:jerry 没有被定义。

    (字符串没有加引号、名称拼写错误、……)

    1.2 数据类型简介和检测

    1.2.1 JavaScript 中两大数据类型

    (1)基本数据类型

    JS 没有字符型,JS 的 String 是基本类型!

    • Number
    • String
    • Boolean
    • Undefined
    • Null

    (2)复杂数据类型

    • Object
    • Array
    • Function
    • RegExp(正则表达式)
    • Date
    • Map
    • Set
    • Symbol
    • ……

    1.2.2 typeof 运算符

    使用 typeof 运算符可以检测值或者变量的类型。
    语法:typeof 变量
    它会返回一个用于描述类型的字符串作为结果

    typeof 是一个运算符,而不是内置函数,所以不用加 (),如果加了也不会报错,但是并不推荐。

    typeof 5;		  // number
    typeof 'ds';	// string
    
    • 1
    • 2

    利用浏览器控制台进行交互测试。

    console.log(typeof 5);
    console.log(typeof "ds");
    var a = "5";
    console.log(typeof a);
    
    • 1
    • 2
    • 3
    • 4

    从以上测试也可以看出,JS 是一个弱类型的语言,变量值是什么类型,那么变量就是什么类型,而不用显式地指出类型。

    1.2.3 5种基本类型的 typeof 结果

    类型名typeof 检测结果值举例
    数字类型number52.5
    字符串类型string'慕课网'
    布尔类型booleantruefalse
    undefined 类型undefinedundefined
    null 类型object(可以理解为空对象)null

    1.2.4 复杂数据类型简介

    除基本类型值外,JS 的世界中还有复杂数据类型。

    举例:

    [1, 2, 3]
    
    { a: 1, b: 2 }
    
    function() {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在 JS 中普通类型也可以包装为复杂类型(对象)

    str01 = "zjr";
    str02 = new String("zjr");
    str03 = String("zjr");
    console.log(typeof str01);		// string
    console.log(typeof str02);		// object
    console.log(typeof str03);		// string
    console.log(str01 === str02);	// false
    console.log(str02 === str03);	// false
    console.log(str01 === str03);	// true
    // Number、Boolean 同理
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    复杂数据类型都是 “引用类型”(type: object),将在后续课程中介绍。

    1.3 String(字符串)类型

    1.3.1 字符串的表示

    字符串要用引号包裹,双引号或者单引号均可。

    typeof "ds";	// string
    typeof 'ds';	// string
    
    • 1
    • 2

    数字 10 和字符串 "10" 在语义上是不同的,前者表示一个数量,后者是一个文本。

    1.3.2 字符串的拼接

    加号可以用来拼接多个字符串。

    "d" + "s";	// "ds"
    "abc" + "d" + "ef";	// "abcdef"
    
    • 1
    • 2

    1.3.3 字符串和变量的拼接

    要将一个变量的值 “插入” 到字符串中,要满足变量左右两边至少有一边 + 字符串。

    var year = 2022;
    var str = "北京冬奥会在" + year + "年召开";	// "北京冬奥会在2022年召开"
    
    var a = 24;
    var str1 = 54 + a;		// 78
    var str2 = "54" + a;	// "5424"
    
    1 + "10"; // "110"
    
    2 + "";	// "2"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ES6 中增加了反引号 ( ` ) 表示法,可以更方便进行变量插值,后续课程将进行介绍。

    1.3.4 空字符串

    一些时候需要使用空字符串,直接书写闭合的引号对即可。

    var str = "";
    
    • 1

    空字符串可以用于将变量变为字符串!

    var a = 24;
    console.log(typeof a);	// number
    a = a + "";
    console.log(a);	// "24"
    console.log(typeof a);	// string
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.3.5 字符串的 length 属性

    通过对 String 类型 “打点” 的方式,可以调用其内置属性。

    注意:在 JS 中,String 是基本类型,之所以 String 可以 “打点” 调用属性和方法,那是因为 JS 的解释器会自动将基本类型包装成对应的对象类型。

    字符串的 length 属性表示字符串的长度。

    "我喜欢JS".length;	// 5
    "我喜欢JS,我也喜欢NODE".length;	// 14
    "".length;	// 0
    
    • 1
    • 2
    • 3

    1.3.6 转义字符

    在字符串中使用\作为转义字符

    \'  ==> '  
    \"  ==> "  
    \n  ==> 换行  
    \t  ==> 制表符  
    \\  ==> \	  
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.4 Number(数字)类型

    1.4.1 一切数都是数字类型

    在 JS 中,所有数字不分大小、不分整浮、不分正负,都是数字类型。

    typeof 925; // number
    typeof 0.5; // number
    typeof -24; // number
    
    • 1
    • 2
    • 3

    1.4.2 小数中 0 可以省略

    在表达小数的时候,整数个位的 0 可以省略。

    1.4.3 科学计数法

    较大数或较小数(绝对值较小)可以写成科学计数法。

    3e8;			// 300000000
    typeof 3e8;		// number
    
    3e-4;			// 0.0003
    typeof 3e-4;	// number
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.4.4 不同进制的数字

    (1)二进制数值以 0b 开头

    0b10;	// 2
    0b1111;	// 15
    
    • 1
    • 2

    (2)八进制数值以 0 开头

    017;	// 15
    
    • 1

    (3)十六进制数值以 0x 开头

    0xf;	// 15
    
    • 1

    1.4.5 一个特殊的数字型值 NaN

    NaN 是 “not a number” 的意思,即 “不是一个数”,但它是一个数字类型的值。

    typeof NaN;	// number
    
    • 1
    • 0 除以 0 的结果是 NaN,事实上,在数学运算中,若结果不能得到数字,其结果往往都是 NaN
    • NaN 有一个 “奇怪” 的性质:不自等(这个知识点将在后续课程中讲解)
    0 / 0;	// NaN
    5 - 3;	// 2
    "我" - "你";	// NaN
    "我" * "你";	// NaN
    "我" / "你";	// NaN
    "我" + "你";	// "我你"
    NaN == NaN;   // false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    再次强调:NaN 是一个值(特殊的值),不是类型。

    唯一能判断 NaN 的方法是通过 isNaN() 函数:

    isNaN(NaN); // true
    
    • 1

    1.5 Boolean(布尔)类型

    在计算机领域,几乎所有的 “真” 和 “假” 都归为布尔类型值。

    布尔类型值只有两个:truefalse,分别表示

    typeof true;	// boolean
    typeof false;	// boolean
    
    • 1
    • 2

    布尔类型在 关系运算 和 逻辑运算 中广泛运用。

    3 < 5;	 // true
    5 > 3; 	 // true
    5 >= 100; // false
    
    • 1
    • 2
    • 3

    注意:在 JS 中,1 可以 “代表” true,0或-0 可以 “代表” false,原理是类型的自动转换,但非常不建议以数字来代替布尔值!

    1.6 Null 类型

    null 表示 “空”,可以理解为它是 “空对象”。

    当我们需要将对象销毁、数组销毁或者删除事件监听时,通常将它们设置为 null。

    box.onclick = null;
    // 删除点击事件
    
    • 1
    • 2

    用 typeof 检测 null 结果为 object

    typeof null;	// object
    
    • 1

    狭义上,null 可以理解为 “空对象”,这样可以合理的解释为什么 null 的类型为 object。

    但是准确的来说,null 不是一个 “对象”,它是一个独立的 “基本数据类型”。

    1.7 Undefined 类型

    一个没有赋值的变量的默认值是 undefined,而 undefined 的类型也是 undefined。

    即:undefined 既是类型,又是值(且这种类型只有它自身一个值)。

    typeof undefined;	// undefined
    
    • 1

    实际开发中,一般不会给某个变量赋值为 undefined,但是我们会检查一个变量的值是否为 undefined。

    在变量声明提升的时候,会出现 undefined,要注意!

     *	null == undefined true
     *	null === undefined false
    
    • 1
    • 2

    1.8 类型转换

    1.8.1转成String

    String()toString()除了对于null和undefined的处理方式不一样,其它一样

    使用 String() 函数

    String() 函数是 JS 内置函数。

    由于 String() 属于内置构造函数,所以 String() 的首字母 S 要大写。

    (1)数字——>字符串

    变为 “长得相同” 的字符串。

    科学计数法和非 10 进制数字会转为 10 进制的标准值。

    String(123);		// '123'
    String(123.4);		// '123.4'
    String(2e3);		// '2000'
    Stiing(NaN);		// 'NaN'
    String(Infinity);	// 'Infinity'
    String(0xf);		// '15'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (2)布尔值——>字符串

    变为 “长得相同” 的字符串。

    String(true);		// 'true'
    String(false);		// 'false'
    
    • 1
    • 2

    (3)undefined 和 null——>字符串

    变为 “长得相同” 的字符串。

    String(undefined);	// 'undefined'
    String(null);		// 'null'
    
    • 1
    • 2

    使用 toString() 方法

    toString() 是几乎所有值都有的方法,功能是将值转为字符串。

    纯数字不能直接 “打点” 调用 toString() 方法,要把纯数字用 () 包裹起来,此时 JS 会提升该数字为一个对象(包装为对象)。

    toString() 方法依旧是返回一个字符串,并不改变变量原有的类型!

    1.8.2 转成Number

    使用 Number() 函数

    Number() 函数是 JS 内置函数。

    由于 Number() 属于内置构造函数,所以 Number() 的首字母 N 要大写。

    (1)字符串——>数字

    Number('123');			 // 123
    Number('123.45');		 // 123.45
    Number('-123');			 // -123
    Number('-123.45');		 // -123.45
    // 字符串中不支持有非数值字符
    Number('123年');	    	// NaN
    Number('2e3');			// 2000
    Number('');				// 0
    
    // 字符串不支持是数学表达式
    Number('1+1');			// NaN
    // 除了字符串外,还可以直接放一个表达式
    Number(1+1);			// 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (2)布尔值——>数字

    Number(true);			// 1
    Number(false);			// 0
    
    • 1
    • 2

    (3)undefined和null——>数字

    Number(undefined);		// NaN
    Number(null);			// 0
    
    • 1
    • 2

    使用 parseInt() 函数

    parseInt() 函数的功能是将 字符串浮点数 转为 整数

    • 自动截掉第一个非数字字符之后的所有字符
    parseInt('3.14');		  // 3
    parseInt('-3.14');		  // -3
    parseInt('3瓜皮.14');	// 3
    parseInt(3.14);		  	  // 3
    parseInt(-3.14);		  // -3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 所有文字都将被截掉
    parseInt('3.14是圆周率');	// 3
    
    • 1
    • 如果字符串以非数字开头,则转为 NaN
    parseInt('圆周率是3.14');	// NaN
    parseInt('一二三');		 // NaN
    
    • 1
    • 2
    • 不存在 “四舍五入”
    parseInt('3.99');		  // 3
    
    • 1
    • true、false、undefined、null 转为 NaN

    之所以会出现这种情况的原因是,parseInt() 的原理是,先将参数转换为字符串,再将字符串转为整数。

    所以,true 等会先被转为 'true'

    parseInt(true);			// NaN
    parseInt(false);		// NaN	
    parseInt(undefined);	// NaN
    parseInt(null);			// NaN
    
    • 1
    • 2
    • 3
    • 4

    parseInt() 函数的特性会用于处理数字的净化。

    parseInt('24px');	// 24
    // 去除了单位,保留数值!
    
    • 1
    • 2

    使用 parseFloat() 函数

    parseFloat() 函数的功能是将字符串转为浮点数。

    绝大部分原理与 parseInt() 类似。

    parseFloat('3.14');		// 3.14
    parseFloat(3.14);		// 3.14
    
    parseFloat('3.14是圆周率');		// 3.14
    parseFloat('3.14.15');		   // 3.14
    
    parseFloat('3.99');			// 3.99
    parseFloat('-3.99');		// -3.99
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1.8.3 其他值——>布尔值

    Boolean() 函数是 JS 内置函数。

    由于 Boolean() 属于内置构造函数,所以 Boolean() 的首字母 B 要大写。

    (1)数字——>布尔值

    0 和 NaN 转为 false,其他数字都转为 true

    Boolean(123);			// true
    Boolean(0);				// false
    Boolean(NaN);			// false
    Boolean(Infinity);		// true
    Boolean(-Infinity);		// true
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Infinity 属性用于存放表示正无穷大的数值。

    (2)字符串——>布尔值

    空字符串变为 false,其他都转为 true

    Boolean('');				// false
    Boolean('abc');				// true
    Boolean('false');			// true
    
    • 1
    • 2
    • 3

    (3)undefined和null——>布尔值

    转为 false。

    Boolean(undefined);				// false
    Boolean(null);					// false
    
    • 1
    • 2

    1.4.12代码块

    			 *
    			 * 我们的程序是由一条一条语句构成的
    			 * 	语句是按照自上向下的顺序一条一条执行的
    			 *JS中可以使用{}来为语句进行分组,
    			 * 		同一个{}中的语句我们称为是一组语句,
    			 * 		它们要么都执行,要么都不执行,
    			 * 		一个{}中的语句我们也称为叫一个代码块
    			 * 		在代码块的后边就不用再编写;* 
    			 * 	JS中的代码块,只具有分组的的作用,没有其他的用途
    			 * 		代码块内容的内容,在外部是完全可见的
    			 *
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    			{
    				var a = 10;	
    				alert("hello");
    				console.log("你好");
    				document.write("语句");
    			}
    			console.log("a = "+a);    
                //let是块级作用域,只能在同一作用域才能访问到
                {
    						let b = 11;
    			}
    			console.log(b);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    第三章 shell条件测试
    web3 从redux中拿出所有已完成订单 并渲染到对应的Table列表中
    .NET开源、强大的Web报表统计系统
    8、【办公自动化】Python实现PDF文件的批量操作
    pytorch训练错误记录
    数据库连接池
    vue3面试题八股集合——2024
    通过图卷积网络从单词语义学习到句子句法,用于基于方面的情感分析
    PCL 基于全局最大一致点集进行点云配准
    ChatGPT Prompting开发实战(十三)
  • 原文地址:https://blog.csdn.net/DSelegent/article/details/126325605