JavaScript 第一章基础


参考文章
https://www.liaoxuefeng.com/wiki/1022910821149312/1023020745357888
菜鸟教程
维基百科

一、JavaScript

1、历史

要了解JavaScript,我们首先要回顾一下JavaScript的诞生。

在上个世纪的1995年,当时的网景公司正凭借其Navigator浏览器成为Web时代开启时最著名的第一代互联网公司。

由于网景公司希望能在静态HTML页面上添加一些动态效果,于是叫Brendan Eich这哥们在两周之内设计出了JavaScript语言。你没看错,这哥们只用了10天时间。

为什么起名叫JavaScript?原因是当时Java语言非常红火,所以网景公司希望借Java的名气来推广,但事实上JavaScript除了语法上有点像Java,其他部分基本上没啥关系。

详细内容请看

2、简介

JavaScript ,通常缩写为 JS,是万维网的一种编程语言和核心技术,与 HTML 和 CSS 并驾齐驱。99%的网站在客户端使用JavaScript进行网页行为,通常包含第三方库。所有主要的 Web 浏览器都有一个专用的 JavaScript 引擎,用于在用户的设备上执行代码。

JavaScript 是一种高级的、通常是实时编译的语言,符合 ECMAScript 标准。它具有动态类型、基于原型的面向对象和一流的功能。它是多范式的,支持事件驱动的、函数式的和命令式的编程风格。它具有用于处理文本、日期、正则表达式、标准数据结构和文档对象模型 (DOM) 的应用程序编程接口 (API)。

ECMAScript 标准不包括任何输入/输出 (I/O),例如网络、存储或图形设施。在实践中,Web 浏览器或其他运行时系统为 I/O 提供 JavaScript API。

JavaScript 引擎最初仅用于 Web 浏览器,但现在已成为某些服务器和各种应用程序的核心组件。对于这种用法,最流行的运行时系统是 Node.js。

尽管 Java 和 JavaScript 在名称、语法和各自的标准库上相似,但这两种语言截然不同,并且在设计上有很大差异。JavaScript在语言设计上主要受到了Self(一种基于原型的编程语言)和Scheme(一门函数式编程语言)的影响,在语法结构上它和C语言很相似(如if条件语句、switch语句、while循环和do-while循环等)

JavaScript与Java在名字和语法上都很相似,但这两门编程语言从设计之初就有很大不同。JavaScript在语言设计上主要受到了Self(一种基于原型的编程语言)和Scheme(一门函数式编程语言)的影响,在语法结构上它和C语言很相似(如if条件语句、switch语句、while循环和do-while循环等)。

对于客户端来说,JavaScript通常被实现为一门解释语言,但如今它已经可以被即时编译(JIT)。随着HTML5和CSS3语言标准的推行,它还可以用于游戏、桌面和移动应用程序的开发,以及在服务器端网络环境运行(如Node.js)。

3、JScript的兴起

1996 年 11 月,Netscape 向 Ecma International 提交了 JavaScript,作为所有浏览器供应商都可以遵守的标准规范的起点。这导致了 1997 年 6 月第一个 ECMAScript 语言规范的正式发布。
标准过程持续了几年,1998 年 6 月发布了 ECMAScript 2,1999 年 12 月发布了ECMAScript 3。ECMAScript 4 的工作始于 2000 年。

与此同时,Microsoft浏览器市场占据了越来越大的主导地位。到 2000 年代初,Internet Explorer 的市场份额达到 95%。这意味着 JScript 成为 Web 上客户端脚本编写的事实标准。
Microsoft最初参与了标准过程,并用其JScript语言实现了一些建议,但最终它停止了在Ecma工作方面的合作。因此,ECMAScript 4 被封存了。

因为网景开发了JavaScript,一年后微软又模仿JavaScript开发了JScript,为了让JavaScript成为全球标准,几个公司联合ECMA(European Computer Manufacturers Association)组织定制了JavaScript语言的标准,被称为ECMAScript标准。
所以简单说来就是,ECMAScript是一种语言标准,而JavaScript是网景公司对ECMAScript标准的一种实现。

ECMAScript版本其实就是JavaScript 版本

4、JavaScript 中重要的AJAX

微软不正干,浏览器市场慢慢被抢一大半

2005年,Jesse James Garrett发布了一份白皮书,其中他创造了Ajax一词,并描述了一套技术,其中JavaScript是骨干,用于创建可以在后台加载数据的Web应用程序,避免了重新加载整页的需要。这引发了JavaScript的复兴时期,由开源库和围绕它们形成的社区带头。创建了许多新库,包括jQuery、Prototype、Dojo Toolkit和MooTools。

在 2000 年代初期 Internet Explorer 占主导地位的时期,客户端脚本停滞不前。这种情况在2004年开始改变,当时Netscape的继任者Mozilla发布了Firefox浏览器。Firefox受到许多人的欢迎,从Internet Explorer中占据了重要的市场份额。

谷歌于2008年首次推出Chrome浏览器,其V8 JavaScript引擎比竞争对手更快。关键的创新是及时编译(JIT),因此其他浏览器供应商需要为JIT彻底改革他们的引擎

2008年7月,这些不同的政党聚集在一起,在奥斯陆举行会议。这导致在2009年初达成了最终协议,将所有相关工作结合起来,推动语言向前发展。结果是2009年12月发布的ECMAScript 5标准。

二、ES6

1、ES历史

  1. 1996 年 11 月,Netscape 向 Ecma International 提交了 JavaScript,ECMAScript 1
  2. 1998 年 6 月发布了 ECMAScript 2。
  3. 1999 年 12 月发布了 ECMAScript 3。
  4. ECMAScript 4 的工作始于 2000 年。
  5. 2009 年 12 月发布的 ECMAScript 5 标准。(2008年7月,这些不同的政党在奥斯陆召开了一次会议。这导致了 2009 年初的最终协议,将所有相关工作结合起来并推动语言向前发展。)
  6. 2015 年发布了 ECMAScript 6 时正式确定了大量的补充和改进( ECMAScript 2015(ES2015))

ECMAScript 6.0(以下简称 ES6,ECMAScript 是一种由 Ecma国际(前身为欧洲计算机制造商协会,英文名称是EuropeanComputerManufacturersAssociation)通过ECMA-262标准化的脚本程序设计语言)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了,
并且 从 ECMAScript6开始,开始采用年号来做版本。即 ECMAScript2015,就是ECMAScript6。 它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。 每年一个新版本。

  1. 2016年6月 ECMAScript 2016(ES2016),第 7 版,多个新的概念和语言特性
  2. 2017年6月 ECMAScript 2017(ES2017),第 8 版,多个新的概念和语言特性
  3. 2018年6月 ECMAScript 2018 (ES2018),第 9 版,包含了异步循环,生成器,新的正则表达式特性和 rest/spread 语法。
  4. 2019年6月 ECMAScript 2019 (ES2019),第 10 版
  5. 2020年6月 ECMAScript 2020 (ES2020),第 11 版
  6. 2021年6月 ECMAScript 2021 (ES2021),第 12 版
  7. 2022年6月 ECMAScript 2022 (ES2022),第 13 版

2、ES6新特性

  • 待编写

ECMAScript 2015(ES2015),第 6 版,最早被称作是 ECMAScript6(ES6),添加了类和模块的语法,其他特性包括迭代器,Python风格的生成器和生成器表达式,箭头函数,二进制数据,静态类型数组,集合(maps,sets和 weak maps)promise,reflection 和 proxies。作为最早的 ECMAScript Harmony版本,也被叫做ES6 Harmony。

1、let 声明变量

// var声明的变量往往会越域
// let声明的变量有严格局部作用域
{
 var a = 1;
 let b = 2;
 }
 console.log(a); // 1
 console.log(b); // ReferenceError: b is not defined
 // var可以声明多次
// let只能声明一次
var m = 1
 var m = 2
 let n = 3
 // let n = 4
 console.log(m) // 2
 console.log(n) // Identifier 'n' has already been declared
 // var会变量提升
// let不存在变量提升
console.log(x); // undefined
 var x = 10;
 console.log(y); //ReferenceError: y is not defined
 let y = 20;

2、const 声明常量(只读变量)

// 1.声明之后不允许改变
// 2.一但声明必须初始化,否则会报错
const a = 1;
 a = 3; //Uncaught TypeError: Assignment to constant variable.

3、解构表达式。数组解构,对象解构

数组

let arr = [1,2,3];
 //以前我们想获取其中的值,只能通过角标。ES6可以这样:
const [x,y,z] = arr;// x,y,z将与arr中的每个位置对应来取值
//然后打印
console.log(x,y,z);

对象

const person = {
 name: "jack",
 age: 21,
 language: ['java', 'js', 'css']
 }
 //解构表达式获取值,将person里面每一个属性和左边对应赋值
const { name, age, language } = person;
 //等价于下面
// const name = person.name;
 // const age = person.age;
 // const language = person.language;
 //可以分别打印
console.log(name);
 console.log(age);
 console.log(language);
 //扩展:如果想要将name的值赋值给其他变量,可以如下,nn是新的变量名
const { name: nn,age, language } = person;
 console.log(nn);
 console.log(age);
 console.log(language);

4、字符串扩展几个新的 API

ES6为字符串扩展了几个新的API:-includes():返回布尔值,表示是否找到了参数字符串。-startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。-endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

let str = "hello.vue";
 console.log(str.startsWith("hello"));//true
 console.log(str.endsWith(".vue"));//true
 console.log(str.includes("e"));//true
 console.log(str.includes("hello"));//true

字符串模板

模板字符串相当于加强版的字符串,用反引号`,除了作为普通字符串,还可以用来定义多行
字符串,还可以在字符串中加入变量和表达式。

// 1、多行字符串
let ss = `
 <div>
 <span>hello world<span>
 </div>
 `
 console.log(ss)
 // 2、字符串插入变量和表达式。变量名写在${}中,${}中可以放
入JavaScript表达式。
let name = "张三";
 let age = 18;
 let info = `我是${na
 // 3、字符串中调用函数
function fun() {
 return "这是一个函数"
 }
 let sss = `O(∩_∩)O哈哈~,${fun()}`;
 console.log(sss); // O(∩_∩)O哈哈~,这是一个函数

5、函数优化,

函数参数默认值

//在ES6以前,我们无法给一个函数参数设置默认值,只能采用变通写法:
function add(a, b) {
 //判断b是否为空,为空就给默认值1
 b = b || 1;
 return a + b;
 }
 //传一个参数
console.log(add(10));
 //现在可以这么写:直接给参数写上默认值,没传就会自动使用默认值
function add2(a ,b = 1) {
 return a + b;
 }
 //传一个参数
console.log(add2(10))

2不定参数
不定参数用来表示不确定参数个数,形如,…变量名,由…加上一个具名参数标识符组成。
具名参数只能放在参数列表的最后,并且有且只有一个不定参数

unction fun(...values) {
 console.log(values.length)
 }
 fun(1, 2) //2
 fun(1, 2, 3, 4) //4

3箭头函数
ES6中定义函数的简写方式
一个参数

//以前声明一个方法
// var print = function (obj) {
 // console.log(obj);
 // }
 //可以简写为:
var print = obj => console.log(obj);
 //测试调用
print(100);

多个参数

 //两个参数的情况:
var sum = function (a, b) {
 return a + b;
 }
 //简写为:
//当只有一行语句,并且需要返回结果时,可以省略{} ,结果会自动返回。
var sum2 = (a, b)=> a + b;
 //测试调用
console.log(sum2(10, 10));//20
 //代码不止一行,可以用`{}`括起来
var sum3 = (a, b)=> {
 c = a + b;
 return c;
 };
 //测试调用
console.log(sum3(10, 20));//30

4 实战:箭头函数结合解构表达式

//需求,声明一个对象,hello方法需要对象的个别属性
//以前的方式:
const person = {
 name: "jack",
 age: 21,
 language: ['java', 'js', 'css']
 }
 function hello(person) {
 console.log("hello," + person.name)
 }
 //现在的方式
var hello2 = ({ name }) => { console.log("hello," + name) };
 //测试
hello2(person);

6、对象优化

1)、新增的 API
ES6 给 Object 拓展了许多新的方法,如

  • keys(obj):获取对象的所有 key 形成的数组
  • values(obj):获取对象的所有 value 形成的数组
  • entries(obj):获取对象的所有 key 和 value 形成的二维数组。格式:[[k1,v1],[k2,v2],...] - assign(dest, …src) :将多个 src 对象的值 拷贝到 dest 中。(第一层为深拷贝,第二层为浅
    拷贝)
const person = {
 name: "jack",
 age: 21,
 language: ['java', 'js', 'css']
 }
 console.log(Object.keys(person));//["name", "age", "language"]
 console.log(Object.values(person));//["jack", 21, Array(3)]
 
  const target = { a: 1 };
 const source1 = {b: 2 };
 const source2 = {c: 3 };
 //Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。
Object.assign(target, source1, source2);
 console.log(target)//{a: 1, b: 2, c: 3}

2)、声明对象简写

const age = 23
const name = "张三"
// 传统
const person1 = { age: age, name: name }
console.log(person1)
// ES6:属性名和属性值变量名一样,可以省略
const person2 = { age, name }
console.log(person2) //{age: 23, name: "张三"}

3)、对象的函数属性简写

let person = {
	 name: "jack",
	 //以前:
	eat: function (food) {
	 console.log(this.name + "在吃" + food);
	 },
	 //箭头函数版:这里拿不到this
	 eat2: food => console.log(person.name + "在吃" + food),
	 //简写版:
	eat3(food) {
	 console.log(this.name + "在吃" + food);
	 }
 }
 person.eat("apple");

4)、对象拓展运算符

拓展运算符(…)用于取出参数对象所有可遍历属性然后拷贝到当前对象。

// 1、拷贝对象(深拷贝)
 let person1 = { name: "Amy", age: 15 }
 let someone = { ...person1 }
 console.log(someone) //{name: "Amy", age: 15}
 // 2、合并对象
 let age = { age: 15 }
 let name = { name: "Amy" }
 let person2 = { ...age, ...name } //如果两个对象的字段名重复,后面对象字
段值会覆盖前面对象的字段值
console.log(person2) //{age: 15, name: "Amy"}

7、map和reduce

map
map():接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回。

let arr = ['1', '20', '-5', '3'];
 console.log(arr)
 arr = arr.map(s => parseInt(s));
 console.log(arr)

reduce

语法:
arr.reduce(callback,[initialValue])
reduce为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元
素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调
用reduce的数组。
callback(执行数组中每个值的函数,包含四个参数)
1、previousValue(上一次调用回调返回的值,或者是提供的初始值(initialValue))
2、currentValue(数组中当前被处理的元素)
3、index(当前元素在数组中的索引)
4、array(调用reduce的数组)
initialValue(作为第一次调用callback的第一个参数。)

const arr = [1,20,-5,3];
 //没有初始值:
console.log(arr.reduce((a,b)=>a+b));//19
 console.log(arr.reduce((a,b)=>a*b));//-300
//指定初始值:
console.log(arr.reduce((a,b)=>a+b,1));//20
 console.log(arr.reduce((a,b)=>a*b,0));//-0

8、Promise

基础语法

    const promise = new Promise(function (resolve, reject) {
            //执行异步操作
            if (/*异步操作成功*/) {
                resolve(value);//调用resolve,代表Promise将返回成功的结果
            } else {
                reject(error);//调用reject,代表Promise会返回失败结果
            }
        });

   使用箭头函数可以简写为:
        const promise = new Promise((resolve, reject) => {
            //执行异步操作
            if (/*异步操作成功*/) {
                resolve(value);//调用resolve,代表Promise将返回成功的结果
            } else {
                reject(error);//调用reject,代表Promise会返回失败结果
            }
        });
        这样,在promise中就封装了一段异步执行的结果。

设置异步处理的结果
如果我们想要等待异步执行完成,做一些事情,我们可以通过promise的then方法来实现。
如果想要处理promise异步执行失败的事件,还可以跟上catch:

promise.then(function (value) {
 //异步执行成功后的回调
}).catch(function (error) {
 

优化js的多条件连环操作
以前的方式

 $.ajax({
            url: "mock/user.json",
            success(data) {
                console.log("查询用户:", data);
                $.ajax({
                    url: `mock/user_corse_${data.id}.json`,
                    success(data) {
                        console.log("查询到课程:", data);
                        $.ajax({
                            url: `mock/corse_score_${data.id}.json`,
                            success(data) {
                                console.log("查询到分数:", data);
                            },
                            error(error) {
                                console.log("出现异常了:" + error);
                            }
                        });
                    },
                    error(error) {
                        console.log("出现异常了:" + error);
                    }
                });
            },
            error(error) {
                console.log("出现异常了:" + error);

现在的Promise方式

 
        new Promise((resolve, reject) => {
            $.ajax({
                url: "mock/user.json",
                success(data) {
                    console.log("查询用户:", data);
                    resolve(data.id);
                },
                error(error) {
                    console.log("出现异常了:" + error);
                }
            });
        }).then((userId) => {
            return new Promise((resolve, reject) => {
                $.ajax({
                    url: `mock/user_corse_${userId}.json`,
                    success(data) {
                        console.log("查询到课程:", data);
                        resolve(data.id);
                    },
                    error(error) {
                        console.log("出现异常了:" + error);
                    }
                });
            });
        }).then((corseId) => {
            console.log(corseId);
            $.ajax({
                url: `mock/corse_score_${corseId}.json`,
                success(data) {
                    console.log("查询到分数:", data);
                },
                error(error) {
                    console.log("出现异常了:" + error);
                }
            });
        });

再次封装公共方法优化的方式

      let get = function (url, data) { //实际开发中会单独放到common.js中
            return new Promise((resolve, reject) => {
                $.ajax({
                    url: url,
                    type: "GET",
                    data: data,
                    success(result) {
                        resolve(result);
                    },
                    error(error) {
                        reject(error);
                    }
                });
            })
        }
      get("mock/user.json").then((result) => {
            console.log("查询用户:", result);
            return get(`mock/user_corse_${result.id}.json`);
        }).then((result) => {
            console.log("查询到课程:", result);
            return get(`mock/corse_score_${result.id}.json`)
        }).then((result) => {
            console.log("查询到分数:", result);
        }).catch(() => {
            console.log("出现异常了:" + error);
        });

9、模块化

模块化就是把代码进行拆分,方便重复利用。类似java中的导包:要使用一个包,必须先
导包。而JS中没有包的概念,换来的是模块。

模块功能主要由两个命令构成:exportimport

  • export命令用于规定模块的对外接口。
  • import命令用于导入其他模块提供的功能。

export
比如我定义一个js文件:hello.js,里面有一个对象

const util = {
 sum(a,b){
 return a + b;
 }
 }

我可以使用export将这个对象导出:

const util = {
	 sum(a,b){
	return a + b;
	 }
}
 export {util};

当然,也可以简写为:

export const util = {
	 sum(a,b){
	 return a + b;
	 }
 }

export不仅可以导出对象,一切JS变量都可以导出。比如:基本类型变量、函数、数组、
对象。
当要导出多个值时,还可以简写。比如我有一个文件:user.js:

var name = "jack"
 var age = 21
 export {name,age}

省略名称
js提供了default关键字,可以对导出的变量名进行省略

//无需声明对象的名字
export default {
 sum(a,b){
 return a + b;
 }
 }

import
使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这
个模块。
例如我要使用上面导出的util:

/导入util
import util from 'hello.js'
 //调用util中的属性
util.sum(1,2)

//要批量导入前面导出的name和age:
import {name, age} from 'user.js'
 console.log(name + " ,今年"+age +"岁了")

注意有点浏览器语法支持不全

三、js的个人练习题

  1. 输入年份 输入月份 判断该年的该月 有多少天?
  • 1 3 5 7 8 10 12 不管哪一年都是31天
  • 4 6 9 11 不管哪一年都是30天
  • 只有2月不一样:
  • 闰年:29
  • 普通年:28
  • 变量:年 月
  • 判断条件:
  • 1.能整除4且不能整除100 y%40 && y%100!=0
    2.能整除400 y%400
    0
var year=Number(prompt("年份"));
			var moth=Number(prompt("月份"));
			switch(moth){
				case 1:
				case 3:
				case 5:
				case 7:
				case 8:
				case 10:
				case 12:
					alert("31天");
					break;
				case 4:
				case 6:
				case 9:
				case 11:
					alert("30天");
					break;
				case 2:
				if(year%4==0&&year%100!=0&&year%400==0){
					alert("29天");
					
				}else{
					alert("28天");
				}
				break;
			}
  1. 张三为他的手机设定了自动拨号按1:拨爸爸的号按2:拨妈妈的号按3:拨爷爷的号 按4:拨奶奶的号

    	//注意事项: switch跟case的值的比较  是 全等=== 。
    
var hm=Number(prompt("请输号"));
					switch(hm){
						case 1:
							alert("给老爸打");
							break;
						case 2:
							alert("给妈妈打");
							break;
						case 3:
							alert("给爷爷");
							break;
						default:
							alert("你输入的无效");
							break;							
					}

**

3.需求:已知公式:标准体重 = 身高 - 105; 上下浮动5公斤。

**
请实现一个计算器,用户输入身高体重,输出偏胖,偏瘦,标准。

var g=prompt("身高");
		var z=prompt("体重:");
		var bz=g-105;
		var max=bz+5;
		var min=bz-5;
		if(z>max){
			alert("偏重");
		}else if(z<min){
			alert("偏轻");
		}else{
			alert("体重标准");
		}

4.个人所得税
个人所得税=(工资 - 三险一金-个税起征点)税率-速算扣除数
应纳税所得额=(工资 - 三险一金 - 个税起征点)
输入工资;
工资不超过 7662 那么五险一金就按照工资
20%计算超过 7662 五险一金就按照 7662*20%
全月应纳税所得额 税率 速算扣除数(元)
全月应纳税额不超过1500元 3% 0
全月应纳税额超过1500元至4500元 10% 105
全月应纳税额超过4500元至9000元 20% 555
全月应纳税额超过9000元至35000元 25% 1005
全月应纳税额超过35000元至55000元 30% 2755
全月应纳税额超过55000元至80000元 35% 5505
全月应纳税额超过80000元 45%
13505

<script type="text/javascript">
			var gz=Number(prompt("工资是多少"));
			var s;//三险一金
			var yn;//应纳税所得额
			var gr;//个人所得税
			if(gz<7662){
				s=gz*0.2;
			}else{
				s=7662*0.2;
				}
			yn=gz-s-3500;	
			if(yn<=0){
				alert("不好意思你没有资格交税");
				
			}else if(yn>0){
				gr=yn*0.03;	
			}else if(yn>1500 && yn<=4500){
				gr=yn*0.1-105;
			}else if(yn>4500 && yn<=9000){
				gr=yn*0.2-555;
			}else if(yn>9000 && yn<=35000){
				gr=yn*0.25-1005;
			}else if(yn>35000 && yn<=55000){
				gr=yn*0.3-2755;
			}else if(yn>55000 && yn<=80000){
				gr=yn*0.45-555;
			}
			alert("你应该缴纳的个人所得税"+gr);	
		</script>

5.循环
需求:迟到了,罚你写10000遍,我错了,我再也不迟到了!

循环需要哪些内容:
条件:
变量 变化在100次的范围;可以0-99 1-100 200-199
初始值
最大值
代码块:
document.write(“我错了,我再也不迟到了!”)
初始变量的自增
综上所述:循环必须四个条件:
1.初始化变量
2.循环条件
3.循环代码块
4.初始化变量的重新赋值,如果没有就会造成死循环。

计算1-100之和

		var i=1;
		var sum=0;
		while(i<101){
			sum+=i;
			i++;
		}
		alert("和:"+sum); 
			var sum=0;
			for(var i=1;i<101;i++){
				sum+=i;
			}
			alert(sum);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Network porter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值