ES6要点梳理

一、变量/赋值

1、变量

ES6在之前用于定义变量关键字var的基础上新增了let和const关键字。其比较如下:

var:定义变量,可多次赋值,有变量提升功能,可重复定义,无块级作用域
let:定义变量,可多次赋值,无变量提升,有暂时性死区,不可重复定义,块级作用域
const:定义常量,定义的时候就需要赋值,赋值之后不可修改,,无变量提升,有暂时性死区,不可重复定义,块级作用域

块级作用域就是作用域在{}里边。

2、解构赋值

  • 左右两边必须一样
  • 定义和赋值必须同步完成
let [a,b,c] = [12,5,8];   // a=12,b=5,c=8

let arr = [2,3,4];
let [e,f,g] = arr;   // e=2,f=3,g=4

let {a, b, c} = {a:5,b:12,c:88};    // a=5,b=12,c=88

// let {a, b, c} = {5,12,88};    //会报错,因为等号右边不是一个对象,即不是一个合规的东西

//let {a, b, c};
//{a, b, c} = {a:5,b:12,c:88};    // 报错,因为声明和赋值没有同时完成

let [a, b, c] = [12, {a:{n1:5, n2:8}, b:12, c:8},99];    //a=12,b ={a:{n1:5, n2:8}, b:12,c:8},c=99

二、函数

1、箭头函数

//普通函数写法
function 函数名(参数1,参数2){
	函数体
}

// 或者

let 函数名 = function(参数1,参数2){
	函数体
}

// 箭头函数写法
(参数1,参数2) => {
	函数体
}

// 或者

let 函数名 = (参数1,参数2) =>{
	函数体
}
  • 如果有且仅有一个参数,可以省略()
  • 如果函数体仅有一条语句,而且该语句是return,可以省略{}和return
let arr = [2,5,3,7,1,9,44,88,33];
arr.sort((n1, n2) => {return n1-n2;});

// 可以简写为:
arr.sort((n1, n2) => n1-n2); // 1,2,3,5,7,9,33,44,88


// 另一个例子

let show = function(a){
	return a * 3;
}
alert(show(13));  // 39

// 等价于

let show = a => a * 3;   // 即给我一个a,给你一个a*3
alert(show(13));  // 39

2、默认参数

  • 常见的默认参数写法
function show(a,b,c){
	// 给b的默认参数为5,写法有以下3种
	b = b || 5; 
	//if(!b){
	//	 b = 5;
	//}
	//b||=5;
	c||=9;
	console.log(a,b,c);
}
alert(show(12));  //12,5,9
alert(show(12,7,6));  //12,7,6
  • 新的默认参数方法
function show(a,b=5,c=9){
	console.log(a,b,c);
}
alert(show(12));  //12,5,9
alert(show(12,7,6));  //12,7,6

3、参数展开(剩余参数,数组展开)

  • "三个点"的第一个作用:用来接收剩余参数
    剩余参数必须在参数列表的最后位置
function show(a,b,...args){
	console.log(a,b,args);
}
show(12,37,33,55,88,11);   // 12,37,[33,55,88,11]
  • "三个点"的第二个作用:展开一个数组
let arr = [12,5,8];
//...arr    完全等价于   12,5,8
let arr2 = [...arr,5,...arr, 7,8];    // 12,5,8,5,12,5,8,7,8

let arr3 = [5,6,7];
arr3.push(...arr); // 5,6,7,12,5,8


function show1(...args){
	show2(args);
}
function show2(a,b){
	console.log(a,b);
}
show1(12,5);  //12,5

三、数组/JSON

1、 数组

数组共新增了5种方法:均是生成一个新数组,原数组不变。

  • map:映射,即一一对应,一个对一个
let arr = [12,55,88,77];
let arr2 = arr.map(item => item >= 60);  // arr2为arr中分数是否及格
console.log(arr2);  // false,false,true,true
  • filter:过滤,即进去一堆,出来一堆符合条件的
let arr = [12,55,88,77];
let arr2 = arr.filter(item => item % 2 === 0); // arr2为arr中为偶数的数
console.log(arr2);  // 12,88
  • forEach:遍历,对数组的每一项走一遍,类似于普通的for循环,没有返回值
let arr = [12,55,88,77];
let sum =0;
arr.forEach(item => {
	sum = sum + item;
});
console.log(sum); // 232
  • reduce:汇总,即进去一堆,出来一个

用途:

  • reduce()方法可以搞定的东西特别多,就是循环遍历能做的,reduce都可以做,比如数组求和、数组求积、统计数组中元素出现的次数、数组去重等等。

用法:

  • reduce() 方法对数组中的每个元素执行一个由您提供的reduce函数(依次执行),将其结果汇总为单个返回值。 reduce 为数组中的每一个元素依次执行回调函数,接受四个参数:初始值 initialValue(或者上一次回调函数的返回值),当前元素值cur,当前索引index,调用 reduce 的数组arr。

参数:

  • 参数一: callback 函数(执行数组中每个值的函数,包含四个参数):
    prev 必需 (上一次调用回调返回的值,或者是提供的初始值(initialValue))
    cur 必需(数组中当前被处理的元素)
    index 可选 (当前元素在数组中的索引)
    arr 可选 (调用 reduce 的数组)
  • 参数二:initialValue 可选 (表示初始值,作为第一次调用 callback 的第一个参数。)
    提供初始值,cur 从数组第一项开始,若不提供初始值,则 cur 从第二项开始执行,对应的第一次 prev 是数组第一项的值
// 求和(带一个参数)
let arr = [12,55,88,77];
let sum = arr.reduce((initialValue,cur,index) => {
	console.log("initialValue=",initialValue,"       cur=",cur,"        index=",index);
	// initialValue= 12        cur= 55         index= 1
	// initialValue= 67        cur= 88         index= 2
	// initialValue= 155        cur= 77         index= 3
	return initialValue + cur;
});
console.log(sum); // 232


// 求平均值
let arr = [12,55,88,77];
let avg = arr.reduce((initialValue,cur,index) => {
	console.log("initialValue=",initialValue,"       cur=",cur,"        index=",index);
	// initialValue= 12        cur= 55         index= 1
	// initialValue= 67        cur= 88         index= 2
	// initialValue= 155        cur= 77         index= 3
	if(index < arr.length - 1){
		return initialValue + cur;
	}else{
		return (initialValue + cur) / arr.length;
	}
});
console.log(avg); // 58


// 求和(带两个参数)
let arr = [12,55,88,77];
let sum = arr.reduce((initialValue,cur,index) => {
	console.log("initialValue=",initialValue,"       cur=",cur,"        index=",index);
	// initialValue= 10        cur= 12         index= 0
	// initialValue= 22        cur= 55         index= 1
	// initialValue= 77        cur= 88         index= 2
	// initialValue= 165        cur= 77         index= 3
	return initialValue + cur;
}, 10);
console.log(sum); // 242

reduce是一个对数组累积操作的方法,使用时要加上 return 返回累积操作的数据。这样 prev 才能获取上一次执行的结果,否则是 undefined

let arr = [12,55,88,77];
let sum = arr.reduce((initialValue,cur,index) => {
	console.log("initialValue=",initialValue,"       cur=",cur,"        index=",index);
	// initialValue= 12        cur= 55         index= 1
	// initialValue= undefined        cur= 88         index= 2
	// initialValue= undefined        cur= 77         index= 3
});
console.log("sum=",sum);  // undefined

空数组执行 reduce 操作且不提供初始值时reduce会报错

let arr = [];
let sum = arr.reduce((initialValue,cur,index) => {
	// Uncaught TypeError: Reduce of empty array with no initial value
	// at Array.reduce (<anonymous>)
    // at <anonymous>:2:15
	console.log("initialValue=",initialValue,"       cur=",cur,"        index=",index);
});

空数组执行 reduce 操作但是设置了初始值就不会报错

let arr = [];
let sum = arr.reduce((initialValue,cur,index) => {
	console.log("initialValue=",initialValue,"       cur=",cur,"        index=",index);
	return initialValue + cur;
}, 0);
console.log("sum=",sum,"    arr=",arr);  // 0  []
  • from:即Array.from,可以把一个拥有length属性的对象或可迭代的对象(即类数组)变成一个真正的数组。

语法

  • Array.from(object, mapFunction, thisValue);

参数:

  • object:必需,要转换为数组的对象。
  • mapFunction:可选,数组中每个元素要调用的函数。
  • thisValue:可选,映射函数(mapFunction)中的 this 对象。
// 数组去重
var setObj = new Set([1, 2, 3,4,1,2]); // 集合中没有重复的元素,实现去重,不过数组变成了set集合
var objArr = Array.from(setObj); // 将set集合转化为数组类型
console.log("objArr=",objArr); // objArr=[1,2,3,4]


// 用箭头语法和映射函数更改元素的值。
let arr = [1,2,3];
var arr1 = Array.from(arr, x => x * 10);
console.log("arr=",arr,"          arr1=",arr1);  // arr=[1,2,3]    arr1=[10,20,30]

2、JSON

两个变化:

  • 简写:名字和值一样的情况下,可以只写名字;
  • 方法中的function可以不写
let a = 12;
let b = 5;
let json = {a:a, b:b}
console.log("json=",json);   // json= {a: 12, b: 5}
// 简写
let json = {a, b}
console.log("json=",json);   // json= {a: 12, b: 5}


let JSON = {
	a:12,
	b: 5,
	show: function(){
		console.log("a+b=", a+b)
	}
}
JSON.show();   // a+b= 17
// 方法中的function可以不写
let JSON = {
	a:12,
	b: 5,
	show(){
		console.log("a+b=", a+b)
	}
}
JSON.show();   // a+b= 17

四、字符串

1、字符串模版

2个特点:

  • 植入变量
  • 任意折行
// 植入变量
let json = {
	name: "张三",
	age: 18,
};
console.log("我叫"+json.name+",我今年"+json.age+"岁"); // 我叫张三,我今年18岁
//等价于
console.log(`我叫${json.name},我今年${json.age}`); // 我叫张三,我今年18岁


// 任意折行:原样打印
console.log(`abc
   cd
      efg`);
//abc
//   cd
//      efg

2、字符串方法

两个方法:

  • startsWith(): 判断字符串是否以某些特定字符开头;
  • endsWith(): 判断字符串是否以某些特定的字符结尾;
let str = "13567899090";
if(str.startsWith("135")){
	console.log("移动");
}else{
	console.log("联通");
}
// 移动


let str1 = "file.txt";
if(str1.endsWith(".txt")){
	console.log("文本");
}else{
	console.log("其他");
}
// 文本

五、面向对象

1、类

传统的面向对象的JS是一个方法,而且是通过prototype属性为对象添加方法。

// 传统的创建对象的方法
function Person(name,age){
	this.name = name;
	this.age = age;
}
Person.prototype.showName = function(){
	console.log(`我叫${this.name}`);
}
Person.prototype.showAge = function(){
	console.log(`${this.age}`);
}
let p1 = new Person("zhangsan",17);
console.log("p1.name=", p1.name); // p1.name= zhangsan


// 传统的继承
function Worker(name,age,job){
	Person.call(this,name,age);
	this.job = job;
}
Worker.prototype = new Person();
Worker.prototype.constructor = Worker; // 设置构造函数
Worker.prototype.showJob = function(){
	console.log(`我从事${this.job}工作`);
}
let p2 = new Worker("blue",18,"打杂");
console.log("p2.job=", p2.job); //p2.job= 打杂
  • class:
    ES6新增了一个关键字class,用于创建类对象。
  • constructor:
    constructor是构造函数。
  • extend:
    ES6新增了关键字extends,用于继承父类。
  • super:
    super超类,即父类(父类的构造函数)。
class Person{
	constructor(name,age){
		this.name = name;
		this.age = age;
	}
	showName(){
		console.log(`我叫${this.name}`);
	}
	showAge(){
		console.log(`${this.age}`);
	}
}
let p3 = new Person("pink", 13);
console.log("p3.name=", p3.name,"    p3.age=",p3.age); // p3.name= pink     p3.age= 13


class Worker extends Person{
	constructor(name,age,job){
		super(name,age); // 超类,代表父类的构造函数
		this.job = job;
	}
	showJob(){
		console.log(`我是从事${this.job}工作的。`);
	}
}
let p4 = new Worker("black",20,"web");
p4.showJob(); // 我是从事web工作的。

2、bind()

bind():给函数绑定一个固定的this


3、箭头函数的this

  • 普通函数的this:根据调用我的人走,即谁调用我this就是谁,this老变
// 普通函数必须有人调用它才知道this是谁
function (){
	console.log(this); // this不知道是谁,因为没有人调用它
}


setTimeout(function (){
	console.log(this);  // Window,因为setTimeout其实是window.setTimeout
}, 50);


document.onclick = function (){
	console.log(this); // document,因为document在调用它
}


let arr = [12,5,8,99];
arr.a = function (){
	console.log(this);
}
arr.a(); // [12, 5, 8, 99, a: ƒ]    this取决于谁调用它
  • 箭头函数的this:根据我所在的环境,我的环境是谁this就是谁,this恒定
() => {
	console.log(this); // Window 该箭头函数处在全局window的环境下,因此this就是window
}


document.onclick = () => {
	console.log(this); // Window,根据所在的环境是window
}


let arr = [12,5,8,99];
arr.a = () => {
	console.log(this);
}
arr.a(); // Window 


document.onclick = function (){
	let arr = [1,2,3];
	arr.a = () => {
		console.log(this); // document,因为箭头函数在document里边,也就是当前环境是document
	}
	arr.a();
}


// 箭头函数的优先级比bind高(类似于bind失效了)
document.onclick = function (){
	let a = () => {
		console.log(this); //此处的this是document
	}
	setTimeout(a.bind(12), 50);  // document,bind改变this失效,因为箭头函数的优先级比bind优先级高
}

六、promise

promise:可以将一个异步操作同步化,即同步的写法,异步的执行顺序。

  • 同步:串行------一个事情没有做完不能开始另一件事情------简单、方便
  • 异步:并发------一个事情阻塞了,可以开始另一件事情------性能高、体验好
//普通的异步
$.ajax({
	url: '/banner_data',
	success(banners){
		$.ajax({
			url: '/user_data',
			success(user){
				$.ajax({
					url: '/items_data',
					success(items){
						$.ajax({
							url: '/news_data',
							success(news){
								console.log("数据获取成功");
							},
							error(){
								console.log("数据获取失败");
							}
						})
					},
					error(){
						console.log("数据获取失败");
					}
				})
			},
			error(){
				console.log("数据获取失败");
			}
		})
	},
	error(){
		console.log("数据获取失败");
	}
})


// 同步
let banners = $.ajax({url: '/banner_data'});
let user = $.ajax({url: '/user_data'});
let items = $.ajax({url: '/items_data'});
let news = $.ajax({url: '/news_data'});


// promise: 用同步的方法写异步
// 1、创建new一个promise对象
// 2、promise有一个回调函数,回调函数有两个参数,一个是resolve成功,一个是reject失败

let p = new promise((resolve, reject) => {
	$.ajax({
		url: '/banner_data',
		dataType: 'json',  // 设置解析json
		success(json){ // 请求成功的时候调用
			resolve(json);
		},
		error(err){ // 请求失败的时候调用
			reject(err);
		}
	});
});
// then表示promise对象内部的操作完成了之后,就会调用then里边的回调函数,成功调用第一个函数(resolve),失败调用第二个函数(reject)
p.then(json => {
	// json是resolve传出来的
	console.log("成功");
}, 
err => {
	console.log("失败");
});

//Promise.all([])是promise对象上的一个方法,接收一个数组作为参数,数组是一堆promise对象,all是当所有的promise对象执行结束之后执行then方法。
let p1 = new promise((resolve, reject) => {
	$.ajax({
		url: '1.txt',
		dataType: 'json',  // 设置解析json
		success(json){ // 请求成功的时候调用
			resolve(json);
		},
		error(err){ // 请求失败的时候调用
			reject(err);
		}
	});
});
let p2 = new promise((resolve, reject) => {
	$.ajax({
		url: '2.txt',
		dataType: 'json',  // 设置解析json
		success(json){ // 请求成功的时候调用
			resolve(json);
		},
		error(err){ // 请求失败的时候调用
			reject(err);
		}
	});
});
let p3 = new promise((resolve, reject) => {
	$.ajax({
		url: '3.txt',
		dataType: 'json',  // 设置解析json
		success(json){ // 请求成功的时候调用
			resolve(json);
		},
		error(err){ // 请求失败的时候调用
			reject(err);
		}
	});
});

Promise.all([p1,p2,p3]).then(arr => {
	// 	其中arr分别是p1、p2、p3接口的返回数据
	console.log("成功");
}, err => {
	console.log("失败");
});


// jQuery的$.ajax其实返回的是一个promise对象,或者说兼容了promise的对象,包含then方法
$.ajax({url: '3.txt',dataType: 'json'}).then(json => {
	console.log("成功");
}, err => {
	console.log("失败");
})


// 简化的Promise请求
Promise.all([
	$.ajax({url:"1.txt", dataType: "json"}),
	$.ajax({url:"2.txt", dataType: "json"}),
	$.ajax({url:"3.txt", dataType: "json"})
]).then(arr => {
	let [a1,a2,a3] = arr; // a1,a2,a3分别是三个接口返回的数据
	console.log("成功", a1, a2, a3);
}, err => {
	console.log("失败");

1、服务器怎么用

  • 东西(代码和文件)放在www里边;
  • 路径转换: c:\wamp\www\ 变为 http://localhost/

2、promise

  • let p = new promise((resolve, reject) => {
    resolve();
    reject();
    });
  • p.then(() => {}, () => {})

3、回调函数

  • 回调,类似于提醒,或者轮询。
  • 不是定义的人来调用,将回调函数交给谁谁来执行。
  • 不知道什么时候调用,反正到执行条件的时候我叫你。
    回调函数就是函数的一种,是一种行为。
    btn.onclick = function(){
    console.log(“回调函数已执行”);
    }

Promise的作用:解除异步操作,将异步过程同步化
Promise的局限性:带有逻辑的异步操作比较麻烦

promise.all(): 与的关系,所有的请求都成功
promise.race(): 或的关系,只要有一个完成就ok(用于网络测速之类的场景)

七、generator

generator:生成器函数,是对promise的改进版本。

  • 能暂停------yield
  • yield可以往里传参,也可以往出带返回值
// 普通函数
function show(){
	console.log("普通函数");
}


// genneretor函数
function *show(){
	console.log("普通函数");
}


// generator函数不会直接执行函数体,会返回一个generator对象,有一个next对象,从函数开始执行到第一个yield之前。
function *show(){
	console.log("aaa");
	yield;// 暂停标志
	console.log("bbb");
}
let gen = show();
gen.next(); // aaa


gen.next(); // bbb
// 也可以用一个定时器执行下一步
setTimeout(function(){
	gen.next()
}, 5000);



// yield传值(传参数)
function *show(){
	console.log("aaa");
	let a = yield;// 暂停标志
	console.log("bbb"+ a);
}
let gen = show();
gen.next(); // aaa
gen.next(12); // bbb12


// 上边generator方法的执行顺序:
function *show(){
	console.log("aaa");
	yield;
	-----------------------第一个next()方法-------------------------------
	let a = yield;// 暂停标志
	console.log("bbb"+ a);
	-----------------------第二个next()方法:因此yield传值的话应该是在第二个next()种传参数a-------------------------------
}


// yield返回值1
function *show(){
	console.log("aaa");
	yield 55;// 暂停标志
	console.log("bbb");
}
let gen = show();
let res1 = gen.next(); // aaa
console.log(res1); // {value: 55, done: false}  done:是表示该方法是否已经执行完成,即是否执行到return语句
let res2 = gen.next(); // bbb
console.log(res2); // {value: undefined, done: true}


// yield返回值2
function *show(){
	console.log("aaa");
	yield 55;// 暂停标志
	console.log("bbb");
	return 88;
}
let gen = show();  // gen是iterator对象
let res1 = gen.next(); // aaa      res1是一个简单的json对象了
console.log(res1); // {value: 55, done: false}  done:是表示该方法是否已经执行完成,即是否执行到return语句
let res2 = gen.next(); // bbb
console.log(res2); // {value: 88, done: true}  value:表示返回值,也即return的值

箭头函数不支持写成生成器函数。

// generator和promise的配合: $.ajax其实就是promise对象
function *show(){
	let data1 = yield $.ajax({url: "1.txt", dataType: "json"});
	if(data1.a + data1.b > 10){
		let data2 = yield $.ajax({url: "2.txt", dataType: "json"});
		console.log(data2[0]);
	}else{
		let data3 = yield $.ajax({url: "3.txt", dataType: "json"});
		console.log(data3.name);
	}
}
runner(show); // 执行show方法

generator与promise配合的缺点:

  • 不能单独执行,需要外来的runner方法辅助执行----外来的runner不统一、不标准、性能低
  • generator函数不能写成箭头函数

八、async/await

//generetor的写法
function *xxx(){
	...
	let res1 = yield xx; // 用res接收yield传递的结果(参数),yield可以用于暂停
	...
	let res2 = yield xx;
	...
}

// async/await的写法
async function xxx(){   // 去掉*,function前边添加async
	...
	let res1 = await xx; // 将yield换成await即可,await后边可以跟一个promise对象,可以跟一个generator,也可以跟一个值,后边非异步的话就不会等待
	...
	let res2 = await xx;
	...
}


// async/await的使用
function sleep(sec){
	return new Promise((resolve, reject) => {
		setTimeout(function(){
			resolve();
		}, sec*1000);
	});
}
async function show(){
	console.log("a");
	await sleep(1);
	console.log("b");
	await sleep(3);
	console.log("c");
}
show(); // 调用    先打印a,停一秒钟,打印b,再停三秒钟,打印c

 
async function show(){
	let res1 = await $.ajax({url: "1.txt", dataType: "json"});
	let res2 = await $.ajax({url: "2.txt", dataType: "json"});
	let res3 = await $.ajax({url: "3.txt", dataType: "json"});
	console.log("res1=", res1, "      res2=", res2, "          res3=", res3);
}
show(); // 调用    先打印a,停一秒钟,打印b,再停三秒钟,打印c
//箭头函数写法 等价于
(async () => {
	let res1 = await $.ajax({url: "1.txt", dataType: "json"});
	let res2 = await $.ajax({url: "2.txt", dataType: "json"});
	let res3 = await $.ajax({url: "3.txt", dataType: "json"});
	console.log("res1=", res1, "      res2=", res2, "          res3=", res3);
})();
// 匿名函数写法 等价于
(async function (){
	let res1 = await $.ajax({url: "1.txt", dataType: "json"});
	let res2 = await $.ajax({url: "2.txt", dataType: "json"});
	let res3 = await $.ajax({url: "3.txt", dataType: "json"});
	console.log("res1=", res1, "      res2=", res2, "          res3=", res3);
})();

// async/await 将异步同步化
(async function (){
	let res1 = await $.ajax({url: "1.txt", dataType: "json"});
	if(res1.a + res1.b > 10){
		let res2 = await $.ajax({url: "2.txt", dataType: "json"});
		console.log("      res2=", res2);
	}else{
		let res3 = await $.ajax({url: "3.txt", dataType: "json"});
		console.log("          res3=", res3);
	}
})();

// 总结
async function xxx(){
	...
	let 需要接收的结果 = await 需要执行的异步操作;  // 此处的异步操作可以是promise、generator、async等
}

// async 和 await是配合把异步操作同步化的

// async 和 await 的错误处理
async function show(){
	let res1 = await $.ajax({url: "1.txt", dataType: "json"});
	let res2 = await $.ajax({url: "223312.txt", dataType: "json"}); // 假设不存在名称为223312的txt文件,即异步请求会出错
	let res3 = await $.ajax({url: "3.txt", dataType: "json"});
	console.log("res1=", res1, "      res2=", res2, "          res3=", res3);
}
show(); // 报错 404

// try/catch异常捕获
try{
	show();  // 并不能正确的捕获show方法中的异常,因为这种写法是需要show方法执行完成之后捕获异常的
}catch(err){
	console.log("有问题  err=", err);
}
// 正确的异常捕获方法
async function show(){
	try{
		let res1 = await $.ajax({url: "1.txt", dataType: "json"});
		let res2 = await $.ajax({url: "223312.txt", dataType: "json"}); // 假设不存在名称为223312的txt文件,即异步请求会出错
		let res3 = await $.ajax({url: "3.txt", dataType: "json"});
		console.log("res1=", res1, "      res2=", res2, "          res3=", res3);
	} catch(err){
		console.log("有问题  err=", err);
	}
}
show(); // 打印有问题,并报404错误

九、模块化

js原本不支持模块化,ES6自带模块化,比如import等。

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值