最全Es6 - Es11( Es6篇)

文末有其他篇链接

Es6

1、let

ES6新增声明变量的指令 let,它的用法类似与var,他是为了解决var在作用域方面出现的异常情况而新增使用词法作用域或块级作用域的变量

 for (var i = 0; i < 5; i++) {
            setTimeout(function() {
                console.log(i) 
            },1000)
} 
//输出结果 5 5 5 5 5 

 for (let i = 0; i < 5; i++) {
            setTimeout(function() {
                console.log(i) 
            },1000)
} 
// 输出结果 0 1 2 3 4 

特点:
(1) 块级作用域,拥有块级作用域的变量只能在当前当前代码块中使用。不能在外部访问。
(2) let 不会变量提升,所以不能再被声明之前被使用,直到声明let变量的代码之前的区域都被成为暂时性死区
(3) 不允许在同一个作用域下被重复声明
(4) 声明的变量不会成为顶层对象(window)属性

2、const

新增声明变量的指令 const,它与let相似。但是const声明的变量被赋值后不能再改变。(我们可以理解为他是一个常量),并且const声明的变量必须在声明时赋值。

const name = "小明"
      name = "小华" // 错误,const只允许赋值一次
console.log(name)
const age; // 错误 const必须在初始化时赋值

特点:
(1) 块级作用域,拥有块级作用域的变量只能在当前当前代码块中使用。不能在外部访问。
(2) 不会变量提升,所以不能再被声明之前被使用,直到声明let变量的代码之前的区域都被成为暂时性死区
(3) 不允许在同一个作用域下被重复声明
(4) 声明的变量不会成为顶层对象(window)属性
(5) const必须在初始化时赋值
(6) const声明的变量被赋值后不能再改变其值
本质上来说const并不能保证其值是不能改变,只能保证变量指向的那个内存地址不能改动,所以const声明的对象、数组依然可以修改他们的属性方法。

3、字符串模板语法

ES6新增了一个 使用模板字符串语法对字符串进行增强,简化了一些复杂的字符串拼接
模板字符串支持换行等,输出的字符串会自带换行符

`hello
world`

内嵌变量:

`你好!我叫${name}。明年${age+1}岁,来自${city}市。`
//等价于
'你好!我叫' + name + '。明年' + (age + 1) + '岁' + ',来自' + city+'市。'

4、函数默认值

在ES6中函数的参数支持使用默认值,当在调用函数时如果没有给函数传递实参则形参会使用默认值

function test(x = 1, y = 2) {
            console.log(x, y)
        }
        
test() // 1,2
test(undefined, 20) // 1, 20

注:
(1) 传递undefined会使得形参使用默认值
(2) 设置默认值形参后面的所有形参会被函数的length属性忽略
(3) 函数的任何一个形参一旦被设置默认值,函数在声明初始化时。所有的参数都将变为独立作用域的参数

5、函数name属性

在ES6,函数拥有一个name属性,这个属性存储当前函数的函数名

function aaa () {
    console.log(this)
}
console.log(aaa.name) // "aaa"

6、箭头函数

在ES6中允许使用 () => {} 形式声明一个函数

function a (x,y) {
           return x + y + 1
       }
// 上面的函数就等等价于下面的箭头函数
let a = (x, y) => x + y + 1

注:
(1) 箭头函数不能直接设置函数名
(2) 如果函数返回的是 单行表达式,可以省略{}和 return,函数会自动返回箭头后 内容(返回一个对象,必须用()将对象包含)
(3) 若箭头函数有且仅有一个形参,则参数的()可以被省略
(4) 箭头函数自身没有this。函数内部的this指向函数声明的作用域this

(5) 箭头函数不能作为构造函数配合new 关键字使用。箭头函数本身就没有实例
(6) 箭头函数没有arguments对象

7、字符串新增方法

startsWith
startsWith() 方法用于检测字符串是否以指定的子字符串开始,是则返回 true,否则 false。
endsWidth
endsWidth() 方法用于检测字符串是否以指定的子字符串结束,是则返回 true,否则 false。
includes
includes() 方法用于检测字符串是否包含指定的字符串,是则返回 true,否则 false。

str.startsWith(str2) //boolean
str.endsWidth(str2) //boolean
str.includes(str2) //boolean

8、解构

数组解构

let [province, city, district] = ['广东省','广州市','天河区']
// 下标相等的变量会与数组中相同下标项进行匹配

数组解构可以有缺省值

let [, city, district] = ['广东省', '广州市', '天河区']
console.log(city, street) // '广州市'  '天河区'

对象解构

let {name, age, gender} = {
            name: "张三",
            age: 30,
            gender: 1,
        }

对象解构的变量名可以自定义

let {name:myName, age:myAge, gender:myGender} = {
            name: "张三",
            age: 30,
            gender: 1,
        }
console.log(myName,myAge,myGender)

注:
(1) 解构允许嵌套解构
(2) 匹配不到的将会返回undefined
(3) 解构支持默认值

8、展开运算符 (…)

ES6提供了展开运算符,展开数组(Es9开始支持展开对象)

let arr = [1,2,3,4]
let newArr = [...arr, 7] //  [1,2,3,4,7]

注:
(1) 如果出现相同的属性,后者将会替换前者
(2) 在解构中…支持剩余(rest)运算

 let [a, b, ...c] = [1, 2, 3, 4, 5]
// a: 1
// b: 2
// c: [3, 4, 5]

(3) 字符串是一个特殊的数组,所以也可以使用展开运算符

[...'hello']  // ['h', 'e', 'l', 'l', 'o']

(3) 解构,展开运算符, rest运算都可以应用在函数的参数上

9、Array新增API

这里由于内容比较多就不细讲
map 遍历当前数组生成一个新的数组
filter 遍历当前数组生成一个过滤后的新的数组
find 方法返回数组中满足条件的第一个元素的值。否则返回 undefined
findIndex 方法返回数组中满足条件的第一个元素的下标。否则返回 -1
reduce 对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值
fill 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引

了解更多 Array API

10、对象属性简洁写法

ES6允许在对象大括号内键值对同名的情况下简写成一个key值,如果key的值为函数可以简写为 key(){}的形式

let name = '小明'
let age = 18

let obj = {
    name, // 等价于 name: name
    age,
    sayHello() {// 等价于 sayHello: function(){...}
	    console.log('123')
    }
}

11、对象的动态键名

ES6允许在对象大括号中使用[js表达式]的形式让对象的key属性成为动态键名

let key = 'currentKey'
let obj = {
	[key]: 123,  // currentKey: 123
	[key+'2']: 1, // currentKey2: 1
}

12、Symbol

symbol 是一种新增的基本数据类型
Symbol([description]) 返回symbol类型的值

const symbol1 = Symbol();
const symbol2 = Symbol('描述内容');//可为symbol 添加描述文字 (不可改)
console.log(typeof symbol1);//"symbol"

Symbol是唯一的,独一无二的,所以被用于作为对象的键名,来创建一个私有的、不对外暴露的属性

Symbol("foo") === Symbol("foo"); // false

全局共享的 Symbol
使用 Symbol.for() 方法和 Symbol.keyFor() 方法从全局的symbol注册表设置和取得symbol
(1) Symbol.for(key)
使用给定的key搜索现有的symbol,如果找到则返回该symbol。否则将使用给定的key在全局symbol注册表中创建一个新的symbol

const s1 = Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
const s2 = Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol
console.log(s1 === s2)// true

(2) Symbol.keyFor()
Symbol.keyFor(sym) 方法用来获取全局symbol 注册表中与某个 symbol 关联的键

// 创建一个全局 Symbol
var globalSym = Symbol.for("foo");
console.log(Symbol.keyFor(globalSym)); // "foo"

Symbol.iterator迭代器
Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for…of 循环使用。
当需要对一个对象进行迭代时(比如开始用于一个for…of循环中),它的@@iterator方法都会在不传参情况下被调用,返回的迭代器用于获取要迭代的值。

我们可以像下面这样创建自定义的迭代器:

var myIterable = {}
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
[...myIterable] // [1, 2, 3]

更多

13、Promise

Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。Promise 是ES6对异步编程一种解决方案。
一个 Promise 必然处于以下几种状态之一:
(1) 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
(2) 已兑现(fulfilled): 意味着操作成功完成。
(3) 已拒绝(rejected): 意味着操作失败。
只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)

实例方法

prototype.then
then() 方法返回一个 Promise 。它最多需要有两个参数:Promise 的成功和失败情况的回调函数
prototype.catch
catch 方法可以用于您的promise组合中的错误处理,它的行为等同于then方法第二个参数
prototype.finally
在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。一般做一些异步请求的清理工作。

使用:
let p = new Promise(function (resolve, reject) {
	//...异步操作
	resolve('Success!') // 成功调用resolve方法
	//reject('失败了!') // 失败调用reject方法
})    
p.then(
    res => console.log(res) // "Success!"
).catch(
	err => console.error(err) // "失败了!"
).finally(
	() => console.log('异步操作执行完毕,无论成功失败') 
)
静态方法

Promise.all(iterable)
这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。
Promise.allSettled(iterable)
等到所有promises都已敲定(settled)(每个promise都已兑现(fulfilled)或已拒绝(rejected))。返回一个promise,该promise在所有promise完成后完成。并带有一个对象数组,每个对象对应每个promise的结果。
Promise.any(iterable)
接收一个Promise对象的集合,当其中的一个 promise 成功,就返回那个成功的promise的值。
Promise.race(iterable)
当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。
Promise.reject(reason)
返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法
Promise.resolve(value)
返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。

14、Object新增方法

Object.assign
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

const target = { a: 1 };
const obj1= { b: 2 };
const obj2= { c: 3 };
Object.assign(target, obj1, obj2);
//target:{a: 1, b: 2, c: 3}

Object.is()
ES6新增的用来比较两个值是否严格相等的方法,与===的行为基本一致。
使用:

Object.is(v1,v2)//比较 v1 v2

与===的不同:

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

Object.keys()
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。

// simple array
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']

// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']

15、Class

在ES6之前创建一个实例对象都使用的是构造函数的方法。ES6引入了class的概念,通过 class 关键字定义类,作为对象的模板。Class可以看作一个语法糖,他的本质和构造函数差不多。class模板写法让对象原型的写法更加清晰、更符合面向对象编程的语法

class App {
    // 这是一个具名类
}
let app = new App() // 创建 App 类的实例对象 
let Demo = class {
    // 这是一个匿名类
}
let demo = new Demo() // 创建 Demo 类的实例对象 

虽然说class本质上是一个function,但它和构造函数也存在不同
(1)函数声明和类声明之间的一个重要区别在于, 函数声明会提升,类声明不会。
(2)class 只允许使用new关键字创建实例对象, 而不允许像构造函数一样直接调用。

constructor
constructor方法是一个特殊的方法,这种方法用于创建和初始化一个由class创建的对象。一个类只能拥有一个名为 “constructor”的特殊方法。如果类包含多个constructor的方法,则将抛出 一个SyntaxError 。
一个构造函数可以使用 super 关键字来调用一个父类的构造函数。
当class中没有显式声明constructor时,会默认的隐式添加constructor方法

 class App {
	constructor(name, age) {
		// 这里的this就是实例对象自身
		this.name = name
		this.age = age 
	}
}
let app = new App('小明', 12)

继承了父类的子类在其constructor函数中一定要调用一个super函数,否则新建实例会报错。

get/set
class可以在内部使用get 和 set 关键字对某个属性设置 get函数和set函数,拦截该属性的存取行为

class ObsVue {
	_count = 0
    // 设置赋值拦截函数 当给this.count赋值时该方法会被调用
	set count(value) {
		console.log('每次给this.count 赋值都会触发set方法',value)
		this._count = value
	}
    // 设置取值拦截函数 当获取this.count时该方法会被调用
    get count() {
    	// 每次获取this.count属性值 都会调用该函数
		// get 方法一定要有return值,他的返回值就是当前属性的值
        return this._count
	}
}

静态方法和静态属性
使用关键字static 声明 静态方法/静态属性,不会被实例对象继承

class App {
       static val = '静态属性'
       test () {
                console.log('原型方法')
       }
       static demo () {
                console.log('静态方法')
       }
}
let app = new App()
App.demo() // 只能通过类自身调用
console.log(App.val) // '静态属性'

extends
extends 关键字在 类声明 或 类表达式 中用于创建一个类作为另一个类的一个子类

class Animal {
  constructor(name) {
    this.name = name;
  }
  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}
class Dog extends Animal {
  constructor(name) {
    super(name); // 调用超类构造函数并传入name参数
  }
}
var d = new Dog('旺财');
d.speak();//调用成功,说明继承了父类speak方法

super()调用父类构造函数

super
super 关键字用于调用对象的父对象上的函数。

class Cat {
  constructor(name) {
    this.name = name;
  }
  speak() {
    console.log(this.name + ' makes a noise.');
  }
}
class Lion extends Cat {
  speak() {
    super.speak();
    console.log(this.name + ' roars.');
  }
}

16、modules 模块

在js中一直没有模块的概念,将js拆成一些互相依赖小模块。在ES6之前实现模块化使用的是 RequireJS 或者 seaJS(分别是基于 AMD 规范的模块化库, 和基于 CMD 规范的模块化库)。ES6 引入了模块化,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。
ES6的模块化自动采用严格模式。无论你是否在文件头部加上“use strict”。ES6 的模块化分为导出(export) @与导入(import)两个模块。

export

为了获得模块的功能要做的第一件事是把它们导出来。使用 export 语句来完成。
最简单的方法是把它(指上面的 export 语句)放到你想要导出的项前面

export const name = 'square';
export function draw(ctx, length, x, y, color) {
  ctx.fillStyle = color;
  ctx.fillRect(x, y, length, length);
  return {
    length: length,
    x: x,
    y: y,
    color: color
  };
}

你能够导出函数,var,let,const, 和类。export 要放在最外层;比如你不能够在函数内使用 export

一个更方便的方法导出所有你想要导出的模块的方法是在模块文件的末尾使用一个 export 语句,语句是用花括号括起来的用逗号分割的列表。比如:

export { name, draw, reportArea, reportPerimeter };

import
在ES6使用export 关键字在模块中对外公开了接口之后,其他模块就可以通过import关键字加载对外公开接口的模块

import { name, draw } from '/module.js';

as指定别名
export时指定别名:

// inside module.js
export {
  function1 as newFunctionName,
  function2 as anotherNewFunctionName
};

// inside main.js
import { newFunctionName, anotherNewFunctionName } from '/module.js';

import时指定别名:

// inside module.js
export { function1, function2 };

// inside main.js
import { function1 as newFunctionName,
         function2 as anotherNewFunctionName } from '/module.js';
console.log(newFunctionName,anotherNewFunctionName)

整体加载
import给开发者提供了 (*)星号用来指定 export模块对象。因为在js中, *号不可以做变量名的所以在模块的整体加载中需要配合 as 关键字给模块整体 设置一个别名

import * as module from '/module.js'
console.log(module)

17、Set

Set对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用

实例属性

Set.prototype.size
返回 Set 对象中的值的个数

实例方法

Set.prototype.add(value)
在Set对象尾部添加一个元素。返回该Set对象。

Set.prototype.clear()
移除Set对象内的所有元素。

Set.prototype.delete(value)
移除Set中与这个值相等的元素,返回Set.prototype.has(value)在这个操作前会返回的值(即如果该元素存在,返回true,否则返回false)。

Set.prototype.entries()
返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值的[value, value]数组。为了使这个方法和Map对象保持相似, 每个值的键和值相等。

Set.prototype.forEach(callbackFn[, thisArg])
按照插入顺序,为Set对象中的每一个值调用一次callBackFn。如果提供了thisArg参数,回调中的this会是这个参数。

Set.prototype.has(value)
返回一个布尔值,表示该值在Set中存在与否。

Set.prototype.keys() (en-US)
与values()方法相同,返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

Set.prototype.values()
返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

Set.prototype@@iterator
返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

使用:

let mySet = new Set();

mySet.add(1); // Set [ 1 ]
mySet.add(5); // Set [ 1, 5 ]
mySet.add(5); // Set [ 1, 5 ]
let o = {a: 1, b: 2};
mySet.add(o);
mySet.add({a: 1, b: 2}); // o 指向的是不同的对象,所以没问题

mySet.has(1); // true
mySet.has(3); // false
mySet.has(5);              // true
mySet.has(Math.sqrt(25));  // true
mySet.has(o); // true

mySet.size; // 4

mySet.delete(5);  // true,  从set中移除5
mySet.has(5);     // false, 5已经被移除

mySet.size; // 3, 刚刚移除一个值
console.log(mySet);
console.log(mySet.keys());
console.log(mySet.entries());
console.log(mySet.values());

因为Set中的元素只会出现一次,所以它可以用于数组去重

const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)])
// [2, 3, 4, 5, 6, 7, 32]

18、Map

Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值)都可以作为一个键或一个值。

实例属性

Map.prototype.size
返回 Map 对象中的键值对数量。

(常用的)实例方法

Map.prototype.clear()
移除 Map 对象中所有的键值对。

Map.prototype.delete(key)
移除 Map 对象中指定的键值对,如果键值对存在,返回 true,否则返回 false。调用 delete 后再调用 Map.prototype.has(key) 将返回 false。

Map.prototype.get(key)
返回与 key 关联的值,若不存在关联的值,则返回 undefined。

Map.prototype.has(key)
返回一个布尔值,用来表明 Map 对象中是否存在与 key 关联的值。

Map.prototype.set(key, value)
在 Map 对象中设置与指定的键 key 关联的值 value,并返回 Map 对象。

const myMap = new Map();

const keyString = 'a string';
const keyObj = {};
const keyFunc = function() {};

// 添加键
myMap.set(keyString, "和键'a string'关联的值");
myMap.set(keyObj, "和键keyObj关联的值");
myMap.set(keyFunc, "和键keyFunc关联的值");

myMap.size; // 3

// 读取值
myMap.get(keyString);    // "和键'a string'关联的值"
myMap.get(keyObj);       // "和键keyObj关联的值"
myMap.get(keyFunc);      // "和键keyFunc关联的值"

myMap..delete(keyString)//移除

myMap.has(keyString)//false

myMap.clear()

19、for…of

for…of 语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for…of 循环,以替代 for…in 和 forEach() ,并支持新的迭代协议。for…of 允许你遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等

//map
for(let [key,value] of myMap){
	console.log('of==>',key,value);
}
//set
for(let value of mySet){
    console.log('of==>',value);
}

20、Reflect映射

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers (en-US)的方法相同。Reflect不是一个函数对象,因此它是不可构造的。

(常用的)静态方法

Reflect.get(target, name, receiver)
获取对象身上某个属性的值,类似于 target[name]。

Reflect.set(target, name, value, receiver)
将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。

Reflect.defineProperty(target, name, desc)
和 Object.defineProperty() 类似。如果设置成功就会返回 true

Reflect.deleteProperty(target, name)
作为函数的delete操作符,相当于执行 delete target[name]。

Reflect.has(target, name)
判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。

使用:

// Reflect 映射
let obj1 = {}
Reflect.set(obj1,'color','red');
Reflect.set(obj1,'width','100px');
console.log(obj1)//{color:'red',width:'100px'}

Reflect.defineProperty(obj1, 'x', {value: 7})

Reflect.deleteProperty(obj, "color"); // true  

console.log(obj1)//{width:'100px',x:7}

let width = Reflect.get(obj1 ,'width');
console.log(width);

21、Proxy 代理拦截

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

语法:
const p = new Proxy(target, handler)
handler

handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。
所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。

(常用的)handler 对象的方法

handler.get()
属性读取操作的捕捉器。

handler.set()
属性设置操作的捕捉器。

使用:

let obj2={};
// 通过 new Proxy 创建一个新对象
let resObj =  new Proxy(obj2 ,{
    // 获取指定条件的属性值
    get(obj2 , key){
        return obj2[key];
    },
    // 设置指定条件的属性值
    set(obj2,key ,value ){
        if(key == "x"){
            obj2[key] = 100;
        }else {
            obj2[key] = value;
        }
    }
});

resObj.x = 999;
console.log(resObj.x);//100

Generator生成器对象

生成器对象是由一个 generator function 返回的,并且它符合可迭代协议和迭代器协议。

常用方法

Generator.prototype.next()
返回一个由 yield表达式生成的值。

Generator.prototype.return()
返回给定的值并结束生成器。

使用:

function* gen() {
  yield 1;
  yield 2;
  yield 3;
}

var g = gen();

g.next();        // { value: 1, done: false }
g.return("foo"); // { value: "foo", done: true }
g.next();        // { value: undefined, done: true }

下一篇:最全Es6 - Es11( Es7篇)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值