day15 es5和es6

JavaScript的构成

DOM 操作文档的
BOM 操作浏览器
ECMAScript (基础语法)

ECMAScript

ECMAScript简称为ES,(ECMA 欧洲计算机协会),ES分为不同的版本(常用的版本 ES3(常用的所有浏览器都支持 都可以直接解析)、ES5 (大部分的高版本的浏览器都能支持)、ES6(部分浏览器支持 但存在兼容问题 不能直接解析 必须先编译成ES3才能解析 bable.js(es的版本编译的)、ES7…(一般把ES6
以后都称为ES6)))

ES3 (常用版本)
ES5 (更加规范化和更加简易化 2015.10)
ES6 (模块化编程 基于ES5更加简易化 2016.4)

ES5新增内容

严格模式
概述:我们普通书写的js代码 并没有特别多的规范,甚至在某些时候可以随意发挥,这种模式被称为怪异模式。相对而言一种更加规范化的模式被称为严格模式。
严格模式的声明
使用 use strict 进行声明,他的声明位置必须在第一行 (常用于源码书写)
严格模式的特性
声明一个变量必须具备关键词
函数内this不能指向window
函数内arguments形参合实参不同步
禁止八进制方法
函数声明必须在对应的位置进行声明

//怪异模式
// var a = 10
// b = 20
// console.log(a);
// console.log(b);
//严格模式
"use strict"; //声明必须在第一行
//声明一个变量必须要有关键词
c = 30
console.log(c);//c没有被定义
//严格模式中函数内的this不能指向window
function fn(){
console.log(this);
}
fn()// this 是 undefined
//在严格模式中不能使用八进制相关的方法
//严格模式中argument的形参和实参不同步
//严格模式中函数只能在对应的声明函数地方进行声明

数组新增的高阶函数
高阶函数概述:
以函数作为参数的函数叫做高阶函数
新增的相关函数
遍历的函数
foreach(没有返回值)

//高阶函数
var arr = ['a','b','c']
//forEach
//传入的函数里面的三个参数分别是 第一个值 第二个下标 第三个遍历的数组
//forEach没有返回值 js函数里面参数如果不需要可以不传
arr.forEach(function(v,i,arr){
// console.log(v); //里面值
// console.log(i); //下标
console.log(arr); //遍历的数组
})
//省略对应参数
arr.forEach(function(v){
console.log(v);
})

map (返回值是一个数组)

//map
//map跟forEach使用是一样的 但map有返回值 返回一个数组
var mapArr = arr.map(function(v,i,arr){
console.log(v);
})
console.log(mapArr);//[undefined,undefined,undefined]
var mapArr = arr.map(function(v,i,arr){
console.log(v);
return v+i+'你好'
})
console.log(mapArr);

过滤和对应计算的
filter (返回一个数组)

var arr = ['abc','a','bc']
//filter 过滤 传入对应的函数 通过函数来返回条件进行过滤 返回的值为数组
//第一个为值 第二位下标 第三为当前遍历的数组
var filterArr = arr.filter(function(v,i,arr){
//里面包含a返回true 里面没有a返回false
//如果返回值是false 就不会加入到对应的数组 如果返回值为true就会加到对应的数组
return /a/.test(v)
})
console.log(filterArr);//包含a的一个数组 ['abc','a']
var arr = [10,9,8,23,15]
//返回所有大于10的
var filterArr = arr.filter(function(v){
return v>10
})
console.log(filterArr);//[23,15]
var arr = [10,9,8,23,15]

reduce (从前到后 返回一个值)
reduceRight (从后往前 返回一个值)

判断是否存在
//reduce 计算的 计算所有的和
//prev表示前面的总和 第一次prev值为10 第二次为19 current默认从第二个开始
var sum = arr.reduce(function(prev,current,i,arr){
console.log(prev);
console.log(current);
console.log(i);//1
return prev+current
})
console.log(sum);
//调整到第1个开始 current的下标为0
arr.reduce(function(prev,current,i,arr){
console.log(i);//0
console.log(prev);//0
},0)
//求乘积
var v = arr.reduce(function(prev,current){
return prev * current
})
console.log(v);
//reduceRight 从右边开始 从后到前 prev值就是倒数第一个 i从倒数第二个开始
arr.reduceRight(function(prev,current,i,arr){
console.log(i);
})

判断是否存在
some (只要有一个就返回true)

// 查询的相关 条件在于传入的函数的返回的值
var arr = [0,1,2,3]
//根据里面返回的内容来进行判断的 里面只要有true返回 他就是true
var is = arr.some(function(v,i,arr){
return v>2
})
console.log(is);

every (所有都满足条件返回true 不然返回false)

//every 每一个都要满足条件
var is = arr.every(function(v,i,arr){
return v>=0
})
console.log(is);

注意事项
forEach和map的区别(forEach没有返回值 map有返回值)
reduce是用于计算的 reduce传入的函数有四个参数(前面的和(默认为第一个) 当前的值(默认是第二个开始) 当前的下标(默认从1开始)
当前遍历的数组)如果需要调整在后面进行传参。
some和every的区别 (some只要有一个满足条件就返回true every要每个都满足条件才返回true)

手写实现数组的高阶函数

forEach(遍历没有返回值)

var arr = [1,2,3]
//forEach 传入的fn里面要有三个参数分别是值 下标 遍历的数组
function myForEach(fn){
//使用for循环
for(var i=0;i<arr.length;i++){
//调用传入的函数
fn(arr[i],i,arr)
}
}
//调用
myForEach(function(v,i,arr){
console.log(v);//1,2,3
console.log(i);//0,1,2
console.log(arr);//[1,2,3]
})

map (返回一个数组)

var arr = [1,2,3]
//map 返回一个数组 数组里面值就是当前的函数执行后的返回结果
function myMap(fn){
//准备一个返回的数组
var returnArray = []
//使用for循环遍历
for(var i=0;i<arr.length;i++){
//将传入的函数的返回结果接收
var result = fn(arr[i],i,arr)
//添加到对应的返回数组中
returnArray.push(result)
}
//将数组返回
return returnArray
}
//调用
var mapArray = myMap(function(v,i,arr){
return v+'你好'
// console.log(v);
})
console.log(mapArray);//['1你好','2你好'],'3你好']]

filter (返回数组)

var arr = [1,2,3]
//filter 过滤 返回一个数组
function myFilter(fn){
//准备返回的数组
var returnArray = []
//遍历
for(var i=0;i<arr.length;i++){
//接收传入函数的返回值
var flag = fn(arr[i],i,arr)
//判断当前的函数是否返回值为true 为true加入到对应的数组
if(flag){
returnArray.push(arr[i])
}
}
return returnArray
}
//调用
var filterArray = myFilter(function(v){
return v>1
})
console.log(filterArray);//[2,3]

reduce (返回的是值)

var arr = [1,2,3]
//reduce实现
function myReduce(fn,index){
//默认情况下第一次的prevoiseValue值为第一个
var prevoiseValue = arr[0]
//默认的index从1开始
if(typeof index != 'number'){
index = 1
}else{//传入了对应的index就是0 prevoiseValue值也是0
index = 0
prevoiseValue = 0
}
//遍历
for(var i=index;i<arr.length;i++){
//调用方法 将对应前面计算的值给到对应的prevoiseValue
prevoiseValue = fn(prevoiseValue,arr[i],i,arr)
}
return prevoiseValue
}
//调用
var result = myReduce(function(prev,current){
return prev*current
})
console.log(result);//6

some (返回boolean类型 有true返回true 没有返回false)

var arr = [1,2,3]
//some 里面有一个return true 他就返回true 否则返回false
function mySome(fn){
//遍历
for(var i=0;i<arr.length;i++){
//接收对应的函数执行的返回值
var flag = fn(arr[i],i,arr)
//如果返回值有一个为true
if(flag){
//直接返回true
return true
}
}
//默认返回false
return false
}
//调用
var is = mySome(function(v){
return v>2
})
console.log(is);//true

every (返回boolean类型 如果有false就返回false 没有返回true)

var arr = [1,2,3]
//every
function myEvery(fn){
//遍历
for(var i=0;i<arr.length;i++){
//接收对应的函数执行的返回值
var flag = fn(arr[i],i,arr)
//如果返回值有一个为false
if(!flag){
//直接返回false
return false
}
}
//默认返回true
return true
}
//调用
var is = myEvery(function(v){
return v>0
})
console.log(is);//true

字符串新增

字符串模板

var username ='李丹'
var str =`hello${username}`
console.log(str) //hello李丹

改变this指向新增方法

this指向
this在函数内的this指向当前函数的调用的者(全局调用的函数this指向window)
this在对应的对象内的函数指向当前的对象的
this在事件对应的函数内指向当前事件的目标元素
如果需要更改this指向那么我们可以给对应的函数调用对应的方法
相关方法
bind (手动调用)
apply (自动调用 传递一个数组)(如果传递的是数组)
call (自动调用 一个个的数据传递)( 一般常用)

function fn(arg,arg1){
console.log(this);
console.log(arg,arg1);
}
fn() //打印window
var obj = {name:'jack'}
//调用bind方法来更改this指向
//将对应的函数绑定给obj这个对象 bind不会执行函数
//函数调用的bind方法返回的是一个函数 这个函数不会自动调用 需要你手动调用
var v = fn.bind(obj)
//执行函数
v()
//bind方法运用 需要手动调用需要()来调用 传参传入到对应的()里面
fn.bind(obj)('你好','世界')
//apply 自动调用 第一个参数是绑定的对象 第二个参数是传递的参数(以数组进行传递)
fn.apply(obj,['hello','world'])
//call 自动调用 第一个参数是绑定的对象 第二个参数是传递的参数 (以一个个的元素进行传递)
fn.call(obj,'吃饭了吗','睡觉了吗')

apply方法和call方法的区别
apply方法传递的参数以数组形式
call方法传递的参数以元素形式
共同点
apply方法和call方法都会自动调用对应的函数

ES6新增内容

ES6对于字符串,数组,函数,对象,循环,变量修饰关键词、基础数据类型等都有新增
字符串新增方法
startsWith 是否开头
endsWith 是否结尾
includes 是否包含
repeat 平铺

var str = 'abc'
//是否开头 返回boolean类型
//是否以a开头
console.log(str.startsWith('a'));//true
// 是否结尾 返回boolean类型
//是否以a结尾
console.log(str.endsWith('a'));//false
//是否包含 返回boolean类型
//是否包含ac
console.log(str.includes('ac'));//false
//平铺 返回的是一个新的字符串
var newStr = str.repeat(2) //将对于的abc平铺俩遍
console.log(newStr);//abcabc

数组新增方法

普通方法
find 根据条件查找对应的值
findIndex 根据条件查找对应的下标

var arr = [1,2,3]
//普通方法(高阶函数) find findIndex
//根据条件查找 返回找到的第一个内容 没有找到返回undefined
//第一个是值 第二个是下标 第三个是数组
var value = arr.find(function(v,i,arr){
return v>1
})
console.log(value);//2
//根据条件返回找到第一次出现的下标 没有找到返回-1
var index = arr.findIndex(function(v,i,arr){
return v>1
})
console.log(index);//1

手写实现find及findIndex

//find查找值 根据传入函数的返回值作为条件来查找 没有找到返回undefined
var arr = [1,2,3]
function myFind(fn){
//遍历 调用函数
for(var i=0;i<arr.length;i++){
var flag = fn(arr[i],i,arr)
if(flag){
return arr[i]
}
}
}
//findIndex查找下标 根据传入函数的返回值作为条件来查找 没有找到返回-1
function myFindIndex(fn){
//遍历 调用函数
for(var i=0;i<arr.length;i++){
var flag = fn(arr[i],i,arr)
if(flag){
return i
}
}
return -1
}
var value = myFind(function(v){
return v>1
})
var index = myFindIndex(function(v){
return v<1
})
console.log(value,index);

静态方法
Array.from 将对应的伪数组转为数组
Array.of 将对应的传入的元素组成一个新的数组返回

//新增的俩个静态方法
//将伪数组转为数组
var btns = document.querySelectorAll('button') //NodeList 伪数组
// btns.map(function(v){
// console.log(v);
// }) 出错 伪数组没有map方法
//转成数组以后再调用
Array.from(btns).map(function(v){
console.log(v);
})
//将传进去的内容组成一个新的数组出来 返回对应的数组
var newArray = Array.of('a','b','c')
console.log(newArray);

变量修饰关键词
es3存在
var 声明伪全局变量
新增的
let 声明块状作用域变量(不允许重复声明
只在当前的代码块内起作用(块级作用域))
const 声明常量 (声明必须赋值 不允许修改 块级作用域)

// let 声明块级作用域
let a = 10
// let a = 20 不允许重复声明
a = 20
console.log(a);
// 块状作用域及伪全局作用域
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i);//重复打印五次5
},1000)
}
//块级作用域 只在当前的作用范围内容 进入
for(let i=0;i<5;i++){
setTimeout(function(){
console.log(i);//打印0 1 2 3 4
},1000)
}
// const 声明常量
const b = 10
// b = 20 //不允许二次赋值
console.log(b);
//声明必须要赋值
// const c 错的
//const也是块级作用域

const 声明的变量如果是引用数据类型、那么里面值是可以变的

基础数据类型

ES3的基础值类型

String
Number
Boolean
null
undefined
新增的值类型
symbol 独一无二的值
BigInt 大的整型

// 新增的类型
//独一无二的值(栈上面)
var sym = Symbol()
var sym1 = Symbol()
console.log(sym);
console.log(sym = = sym1);//false
var sym2 = Symbol('你好') //传入的参数是说明
var sym3 = Symbol('你好')
console.log(sym2 == sym3);//false
//一般用于对象的key key不能重复的
var obj = { sym:10}
console.log(obj.sym);
//获取详情
console.log(sym2.description);
//BigInt 大的整型 容纳大的数
//Number中的整型Int容纳范围是有限的 10^16
var bi =
BigInt('111111111111111111111111111111111111111111111111111111111111111')
console.log(bi);

循环

for in(遍历对象)
for of (遍历数组的 只要实现了iterable迭代器就可以用for of遍历)

var obj = {
name:'张三',
age: 18
}
for (var key in obj) { //遍历的是key (数组的key是下标)key的类型为字符串
console.log(key)
}
var arr = ['a', 'b', 'c']
for (var value of arr) { //for of遍历的是值
console.log(value)
}

函数的新增

新增函数的默认参数

// 函数新增 默认参数
//默认a为0 b也为0 如果你传递了对应的参数 那么默认值就会被覆盖
function fn(a=0,b=0){
console.log(a+b);
}
fn(1,3)//打印4
fn()//打印0
fn(1)//打印1

新增箭头函数
箭头函数的写法

(参数1,参数2,...参数n)=>{代码}

示例

//新增箭头函数 是一个匿名函数
var fn1 = ()=>{
console.log('我是箭头函数');
}
fn1()

箭头函数的简化写法
如果当前的参数只有一个 ()可以省略的
如果当前的{}里面的代码只有一句的话 {}也可以省略
如果当前的{}里面只有一句代码 且你需要返回数据的时候 可以省略return

//简化写法
// 如果当前的参数只有一个 ()可以省略的
// 如果当前的{}里面的代码只有一句的话 {}也可以省略
// 如果当前的{}里面只有一句代码 且你需要返回数据的时候 可以省略return
var fn2 = arg =>arg+'你好' //当前fn2 传递一个arg 返回一个arg+你好
var result = fn2('hello')
console.log(result);

箭头函数的特性
没有this (根据作用域链向上找)
没有arguments

//箭头函数的特性
var obj = {
say:function(){
console.log(this);
console.log(arguments);
}
}
obj.say() //打印obj
var obj = {
say:()=>{
console.log(this);
console.log(arguments);
}
}
obj.say() //打印window
//箭头函数里面没有this 所以他会去上面找 根据作用域链找离他最近的
//箭头函数里面没有arguments

对象新增

新增对象方法(静态方法)
Object.is 判断俩个对象是否是一个 返回对应true和false

// Object.is 用于判断俩个对象是否是同一个对象
console.log({} = = {});//false 比较地址值
console.log({} = = = {});//false 比较地址值比较类型
console.log(Object.is({},{}));//false 比较地址值同时还要比较类型
//特殊值 (可以解决NaN不等于NaN问题)
console.log(NaN = = NaN); //false
console.log(NaN === NaN);//false
console.log(Object.is(NaN,NaN));//true

Object.assign 将后面对象的内容拷贝到前面的第一个对象

//Object.assign 将后面的内容拷贝到前面 返回一个对象 而这个对象的地址和第一个对象的地址完全一var obj = {name:'jack'}
var targetObj = Object.assign(obj,{age:18},{sex:'男'},{height:189})
console.log(targetObj);//{name:jack,age:18,sex:男,height:189}
console.log(targetObj == obj);//true
//只拷贝第一层的值 剩下的拷贝的是引用地址 (浅拷贝实现方式之一)
var obj1 = {age:18,arr:[1]}
var targetObj = Object.assign({name:'tom'},obj1,{sex:'男'},{height:189})
console.log(targetObj);//{name:tom,age:18,arr:[1],sex:男,height:189}
//让第二层的内容发送变化
obj1.arr[0] = 10
obj.age = 20
//原本拷贝对象的值也会变化
console.log(targetObj);//{name:tom,age:18,arr:[10],sex:男,height:189}

新增对象简化写法
对于对象中的函数可以省略对应的function
对于对象中value变量名和key的名字一致的时候可以省略key

//简化写法
var name =
'
jack'
var obj3 = {
// name:name,
//当你的key和value是一样的时候省略key value一定要是变量
name,
// say:function(){
// console.log('hello');
// }
//对象中函数的简化写法
say(){
console.log('hello');
}
}

解构赋值和扩展运算符

解构赋值(解除构造进行赋值)
{} 对于对象的解构 (使用key来匹配)
[] 对于数组的解构(使用下标来匹配)

var obj = {name:'jack',age:18,sex:'男'}
var arr = ['a1','b2','c3']
//采用解构赋值快速提取 对象
//{} 里面填写的是键 按照填写的key去匹配对象里面key取出他的值
var {name,sex,age} = obj
console.log(name,sex,age);
//[] 对于数组的解构 按照对应的顺序 下标匹配的
var [a,c,b] = arr
console.log(a);//a1
console.log(c);//b2

扩展运算符 (将内容一个个扩展出来)

//扩展运算符 ... 针对于数组的
console.log(...[1,2,3,4,5]);//1 2 3 4 5
//组成一个新的数组
console.log(Array.of(1,2,3,4,5));
console.log(Array.of(...[1,2,3,4,5]));//如果需要逗号隔开他会默认自己加上逗号

新增的集合类型(伪数组)

伪数组其实他也可以使用for of进行遍历(实现迭代器)
set
概述:set是一个不允许重复的集合
set的构建
不传参构建的是一个空的set集合
传入数组由数组里面的元素构建一个集合(数组去重)

//使用new关键词进行操作
//里面可以传入对应实现迭代器iterable的元素
//构建一个空的set集合
var set = new Set()
console.log(set);
//传入一个数组 提取数组中的元素构建一个set集合
var set = new Set([1,2,22,22,2,3,1]) //完成数组去重的功能
console.log(set);//1,2,22,3

set的方法及属性
属性
size

//set的属性 size
console.log(set.size);//size表示长度

方法
add 添加方法
delete 删除方法
clear 清空
has 判断是否存在
forEach 遍历
keys 获取所有的key返回迭代器
values 获取所有的value返回一个迭代器
entries 获取所有的k:v键值对 返回一个迭代器

//相关方法
//增加 add
set.add(22) //如果添加的是重复元素将不能添加进去
set.add('hello') //set中可以存储任意类型数据
console.log(set);
//删除 delete 传入对应的值进行删除
set.delete(22)
console.log(set);
//清空方法 clear
// set.clear()
console.log(set);
//改
// 将对应的内容删除再添加就是改
//查
//has 判断值是否存储 返回boolea类型 如果值存在返回true 不存在返回false
console.log(set.has(1));//false
//forEach 遍历的
set.forEach((v1,v2,s)=>{
//他的key就等于他的value
//v1表示key
console.log(v1);
//v2表示value
console.log(v2);
//s表示当前遍历的set
console.log(s);
})
//keys 获取所有的key values 获取所有的value entries获取所有的key:value键值对 返回的
iterable迭代器(数组)
console.log(set.keys());
console.log(set.values());
console.log(set.entries());//键值对

weakSet 专门存储对象的set

//专门用于存储对象的set set并不能完成对象数组的去重
//无参构建
var ws = new WeakSet()
//有参构建 传入一个只读的对象数组
var ws = new WeakSet([{name:'张三'},{name:'张三'}])
console.log(ws);
//weakSet只有三个方法 has add delete
ws.add({age:18})
console.log(ws.has({age:18}));//false
ws.delete({age:18}) //删除不了 {age:18} != {age:18} 不是一个对象
console.log(ws);

map
概述:map他是一个key:value对 key不允许重复的 value可以重复(抽取所有的key他可以组成一个set,所有的value抽取就是一个数组)
map的构建
无参构建
传入一个二维数组构建

//无参的方式
var map = new Map()
console.log(map);//构建一个空的map
//传递一个二维数组
//里面的元素数组 第一个是key 第二个是值
var map = new Map([['name','jack'],['age',18],['sex','男'],['sex','女']])
console.log(map);

map的属性及方法
属性
size

// 属性 size map里面的元素个数
console.log(map.size);

方法
set 设置
get 通过key来获取value
delete 通过key来删除
clear 清空
has 判断当前的key是否存在
keys 返回所有的key
values 返回所有的value
entires 返回所有的k:v
forEach 遍历

//相关方法
// 增 set
map.set(108,'yes')
console.log(map);
//修改就是对应的本身已经存在的key进行重新的设置
map.set('sex','girl')
console.log(map);
//删除 根据key来删除
map.delete(108)
console.log(map);
//清除所有的
// map.clear()
console.log(map);
//查询
//根据key判断是否存在
console.log(map.has('sex'));
//forEach 第一个值为值 第二个为键 第三个当前遍历map
map.forEach((v,k,map)=>{
console.log(k);
console.log(v);
})
//keys values entries
console.log(map.keys());
console.log(map.values());
console.log(map.entries());
//通过key来获取value
console.log(map.get('sex'));

WeakMap(基于weakSet构建的map)

//weakmap 基于 weakSet之上构建 也就是对应的key是对象 抽取所有的key其实就是weakSet
var wm = new WeakMap()
var wm = new WeakMap([[{name:'hello'},'你好']])
console.log(wm);
// wm.delete
// wm.get
// wm.set
// wm.has

Class 类

概述:类是对象的模板,对象是类的实例。(类相当建房子的设计图,对象相当于建好的房子)
相关知识点
class是用于修饰类的
类名首字母必须大写
class里面的constructor 是一个函数 他会在每次new的时候调用
class中constructor的this关键词指向当前的实例对象
extends关键词是class之间的继承的
如果使用了extends关键词,还想要在construct中使用this 那么必须先调用super方法
对应的super关键词指向父类的constructor
静态方法使用static关键词修饰,调用使用类名.方法名调用

// class是用于修饰类的 类是对象的模板(设计图)
//class修饰的类名必须首字母大写
// class 类名{
// 构造器
// }
//class里面的this 指向当前构建的对象实例
class Person{
//构造器 他是用于构建对象的方法
constructor(name){
this.name = name //this指向你对应构建的对象实例
this.sex = '男'
}
//静态方法 使用类名. 使用static关键词修饰的方法
static say(){
console.log('hello');
}
}
//构建对象使用new关键词
//new 操作符会做那些操作 开辟内存空间(建立一个对象) 存放对应的对象 自动执行对应的构造函数 将
对应的设置设置给到当前对象 然后将对象返回
var person = new Person('jack')
console.log(person);//{name:jack}
//静态方法调用
Person.say()
//继承 除了私有的其他全部可以继承
// extends关键词实现class的继承
class Child extends Person{ //child这个类继承Person类
constructor(name,age){
//如果使用extends关键词那么在对应的构造器里面不能直接使用this 要调用super函数
super(name) //相当于父类的构造函数 Person.constructor
this.age = age
}
}
var child = new Child('tom',88)
console.log(child);//{name:tom,sex:男,age:88}

generator函数

//异步阻断变同步的内容
function* fn(){
yield setTimeout(()=>{console.log('你好');},2000)
yield setTimeout(()=>{console.log('你好世界');},1000)
yield setTimeout(()=>{console.log('hello');},0)
}
var a = fn()
a.next()//打印你好
a.next()//打印你好世界
a.next()//打印hello
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值