ES6(ECMAScript 6)学习——一文搞懂ES6

ES6学习——一文搞懂ES6

es6介绍

ES全称EcmaScript,是脚本语言的规范,而平时经常编写的EcmaScript的一种实现,所以ES新特性其实就是指JavaScript的新特性。

为什么要学习ES6

1.ES6版本变动内容最多,具有里程碑意义。
2.ES6加入了许多新的语法特性,编程实现更简单,高效
3.ES6是前段开发的趋势,就业必备

ES6-let变量声明以及声明特性

声明变量:
es6中的let
let特性

  1. 变量不能重复声明
    ES6let变量不能重复声明
  2. 块级作用域【全局作用域,函数作用域,eval作用域】
    let块级作用域
  3. 不存在变量提升【:代码在执行之前的时候会提前收集变量以及函数,并赋值初始值null和undefined】let不能在变量声明之前去使用,而var可以在被声明之前被使用。
    var的变量提升
    let的变量提升报错
  4. 不影响作用域链
    let不影响作用域链

const的声明及其特点

变量声明【声明常量】
const声明常量
const的使用注意

  1. 一定要赋初始值
    const赋初始值
  2. 潜规则,一般常量使用大写
    const的潜规则
  3. 常量值不能修改
    常量不能修改初始值
  4. 块级作用域
    const的块级作用域
    5.对于数组和对象的元素修改,不算做对常量的修改,不会报错
    const元素修改数组不报错
    const修改值报错

ES6变量的结构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值

  1. 数组的解构
    es6数组的解构
  2. 对象的解构
    es6对象的解构
    为什么要进行对象解构?
    先看代码:
    es6为什么要进行独对象解构
    属性解构使用的比较少,方法解构用的比较多,如果不用方法解构,每次都需要写“zhao.xiaopin()”的形式,就比较重复,那么可以进行对象的解构,调用方式就不需要在前面写“zhao.xxx”的形式;
    方法解构和调用方式
    什么情况下使用方法的解构:
    新特性的产生就是为了让开发者更加方便,发现有重复的地方,就想办法把它去掉,如果遇到方法频繁调用,这个时候就可以想到解构赋值用上,让代码更加简洁。

ES6模板字符串

es6引入新兴的声明字符串的方式es6引入字符串的方式

  1. es6字符串声明
    es6字符串声明
  2. 特性一:内容中可以直接出现换行符
    es6之前出现换行符会出现报错【语法错误】
    es6字符串出现换行符报错
    es6出现后不报错使用 “``” 即可解决语法报错问题。
    es6换行符字符串
  3. 特性二:变量拼接
    es6变量的拼接

es6对象的简化写法

es6允许直接在大括号里面直接写入变量和函数,作为对象的属性和方法,简化程序员书写代码的步骤。

  1. 变量形式简化对象写法
    es6对象的简化写法
  2. 方法声明简化
    es6之前对象方法的繁琐写法
    es6之前对象方法的写法
    es6之后对象方法的简化写法
    es6之后对象方法的简化写法

ES6箭头函数以及声明特点

es6允许使用 [箭头] (=>) 定义函数

  1. 使用原始方法声明一个函数和使用箭头函数声明一个方法
    原始声明函数的方法箭头函数的声明和调用
  2. 箭头函数声明的特性,和之前的函数有什么区别?

一、this是静态的,this始终是指向函数声明时所在作用域下的this的值,箭头函数的this值是静态的,无论使用使用任何方式去调用它,它的this始终是指向函数在声明时所在作用域下的那个this值。
直接调用:箭头函数this的指向
call方法调用:可以改变函数内部this的值,下面的结果可以看出call不能改变箭头函数中this的指向。
call调用箭头函数
二、箭头函数不能作为构造函数来实例化对象
箭头函数不能作为构造函数来实例化对象
三、不能使用arguments变量【函数内部特殊的变量arguments,用来保存实参】
箭头函数不能使用arguments变量
四、箭头函数的简写,两种情况
第一种:是省略小括号,当形参有且只有一个的时候可以省略。
箭头函数省略小括号
第二种:是省略花括号,当代码体只有一条语句的时候,此时return必须省略,而且语序的执行结果就是函数的返回值。
箭头函数省略花括号
箭头函数使用注意事项:

一、 箭头函数适用于this无关的回调,定时器,数组方法的回调
二、 箭头函数不适合与thi有关的回调,事件回调,对象的方法

es6函数参数的默认值设置

es6中允许给函数参数赋值初始值

  1. 形参的初始值
    es6赋初始值
    es6中形参少传递一个出现NaN结果
    es6函数调用形参少传值
    es6给函数赋初始值,如果不传递这个参数,默认值是初始值
    es6给函数形参赋初始值
    注意点:既有默认值的参数,一般位置要靠后(潜规则)

  2. 与解构赋值结合使用
    es6参数与解构赋值结合使用
    如果传了用传的参数,如果没有传使用设置的默认值。

es6中rest参数

es6引用rest参数,用于获取函数的实参,用来代替arguments【获取函数在调用时所有的实参】

  1. es5获取实参数的方式【返回的对象】
    es5获取实参数的方式
  2. es6中的rest参数【返回的是数组】
    es6中的rest参数【返回的是数组】
    返回数组就可以使用"filter",some every,map,提高了对参数处理的灵活程度。
  3. 注意:如果参数有多个,rest参数必须要放到参数的最后。
    错误使用:
    rest参数

正确使用:
rest参数

es6扩展运算符介绍

【…】扩展运算符能将【数组】转换成逗号分割的【参数序列】。

  1. 例子
    不使用…传递,传递数组
    es6扩展运算符介绍
    使用…传递
    es6扩展运算符介绍

扩展运算符的应用

  1. 数组的合并
    es6扩展运算符数组合并
  2. 数组的克隆
    es6扩展运算符的数组克隆
  3. 将伪数组转为真数组
    es6扩展运算符将伪数组转换成真数组

es6-Symbol的介绍与创建

  1. symbol的介绍
    es6引入了一种新的原始数据类型symbol,独一无二的值,他是javascript语言的第七种数据类型,是一种类似于字符串的数组类型。
  2. symbol的特点

一、 symbol的值是唯一的,用来解决命名冲突问题。
二、symbol的值不能与其他数据进行运算。
三、symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名

  1. 创建symbol
    第一种创建方式:
    创建Symbol

第二种创建方式:其中括号内只是symbol的标志
symbol的创建
第三种方式:【Symbol.for()】,symbol.for是一个全局的symbol表,如果有了就访问对应对象,如果没有就创建。
symbol的创建

es6-对象添加symbol类型的属性

使用symbol添加对象和属性,我们可以很快速的很安全的把对象加入game里面,不会破坏原有的属性和方法。

  1. 第一种添加方法
    symbol添加对象
  2. 第二种添加
    为对象添加symbol类型的属性

ES6-Symbol的内置值

除了定义自己使用的Symbol值以外,ES6还提供了很多内置的Symbol值,指向语言内部使用的方法。
ES6-Symbol的内置值
ES6-Symbol的内置值
ES6-Symbol的内置值

  1. Symbol.hasInstance
    2.
  2. isConcatSpreadable
    在这里插入图片描述

es6-迭代器

迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据解构只要部署iterator接口,就可以完成遍历操作。

  1. es6创造了一种新的遍历命令for … of循环,lterator接口主要供for…or消费
  2. 原生具备iterator接口的数据可用for of遍历,Array,Arguments,Set,map,string,typeArray,NodeList
  3. 工作原理
a. 创建一个指针,指向当前数据结构的起始位置。
b. 第一次调用对象的next方法,指针自动指向数据结构的第一个成员,
c. 接下来不断调用next方法,指针一直往后移动,知道只想最后一个成员。
d. 每调用next方法返回一个包含value和done属性的对象
**注意:需要自定义遍历数据的时候要想到迭代器**
  1. for…of循环【输出键值】
    for...of循环
  2. for…in循环【输出键名】
    for...in循环

迭代器应用-自定义遍历数据

根据迭代器的工作原理自定义迭代器遍历数据

 <script>
        //声明一个对象
        const banji = {
            name:"终极一班",
            stus:['小明','小天','小吴','小王',],
            [Symbol.iterator](){
                //索引变量
                let index = 0;
                //指向
                let _this = this;
                return {
                    next:function(){
                        if(index<_this.stus.length){
                            const result = {value:_this.stus[index],done:false}
                            //下标自增
                            index++;
                            //返回结果
                            return result;
                        }else{
                            return {value:undefined,done:true}
                        }
                    }
                }
            }
        }

        //遍历这个对象
        for(let v of banji){
            console.log(v);
        }
    </script>

效果:
迭代器应用-自定义遍历数据

es6-生成器函数声明与调用

生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同,其实就是一个特殊的函数,用来异步编程,之前用的是纯回调函数
node \fs \ ajax\mongodb

  1. 声明与调用方式:
    生成器声明与调用方式:
  2. 生成器可以使用yield语句
    yield可以算作函数代码的分隔符
    生成器可以使用yield语句
    yield语句可以作为分割符使用,使用next调用
    生成器可以使用yield语句
  3. 使用for-of遍历生成器
    使用for-of遍历生成器
  4. 生成器的原理输出解释yield的作用:
    生成器的原理输出解释yield的作用

ES6生成器函数的参数传递

生成器调用的next是可以传递实参的,而这个实参数就是这个yield语句整个返回结果。

  1. 整体函数传参
    es6整体函数传参
  2. next方法也是可以传参的,而且这个参数将作为上一个yeild语句的返回结果,第二次调用返回第一个yeild语句的整体返回结果,。。。
    生成器next方法整体函数传参

es6生成器函数实例

异步编程:文件操作,网络操作(ajax,request)数据库操作
实例:1s输出111 ,2s输出222,3s输出333
层层回调,会变成回调地狱
 es6生成器函数实例
上面代码会进入回调地狱,下面就不行
在这里插入图片描述
实例二、模拟获取,用户数据,订单数据,商品数据
在这里插入图片描述
调用:
生成器函数异步操作

es6-promise学习与使用

es6-promise介绍与基本使用

promise是ES6引入的异步编程的新解决方案,语法上市promise是一个构造函数,用来封装异步操作并可以获取奇成功或失败的结果【解决回调地狱问题】

  1. Promise构造函数 :Promise {excutor}{ }
  2. Promise.prototype.then方法
  3. Promise.prototype.catch方法

1. 实例化Promise对象
Promise对象有三个状态,初始化,成功,失败
实例化promise对象:

//实例化Promise对象【三个状态:初始化,成功,失败】
        const p = new Promise(function(resolve,reject){
            setTimeout(() => {
                let data = "数据库中的用户数据"
                //resolve调用
                resolve(data);
            }, 1000);
        });

调用成功和失败都会执行promise.then的方法,then的方法有两个参数,两个参数都是函数类型的值,每个函数都有一个形参,成功的执行then的第一个函数,失败的执行第二个执行参数,两个函数的形参分别是value和reason,成功的叫做value,失败的叫做reson。
调用then代码:

/*
	 调用成功,就会调用promise对象的then方法,
     then方法接受两个参数,
     两个参数都是函数类型的值,每个函数都有一个形参,成功的叫做value,失败的叫做reason
     调到resolve代表成功,读取状态成功,then就会执行第一个回调函数代码
     如果读取状态失败,调用带有
  */
p.then(
	   function(value){
         console.log(value);
       },
       function(reason){
	   }
)

成功调用输出:
promise实例化成功
读取失败的例子:

 const p = new Promise(function(resolve,reject){
            setTimeout(() => {
                //
                let data = "数据库中的用户数据"
                let err = "读取数据库失败"
                //resolve调用
                reject(err)
            }, 1000);
        });
        p.then(function(value){
            console.log(value);
        },function(reason){
            console.log(reason);
        })

promise实例化读取失败返回结果

es6-promise封装读取文件

原生js输出文件内容【请求文件内容属于异步】

//引入fs模块
const fs = require('fs');

//调用方法读取文件
fs.readFile('./resources/1.md',(err,data)=>{
    //如果失败则抛出错误
    if(err) throw err;
    //如果没有出错,则输出内容
    console.log(data.toString());
})

效果:
js原生读取文件
使用promise封装读取文件:

//3.使用promise封装
const p = new Promise(function(resolve,reject){
    fs.readFile("./resources/1.md",(err,data)=>{
        //判断读取失败
        if(err) reject(err);
        //如果成功
        resolve(data)
    })
})
p.then(
    function(value){
        console.log(value.toString());
    },
    function(reason){
        console.log(reason);
    })

效果:
使用promise封装读取文件
使用promise封装读取文件

es6-promise封装Ajax请求

  1. 原生Ajax请求数据
 <script>
        //接口地址:https://api.apiopen.top/getJoke

        //创建对象
        const xhr = new XMLHttpRequest();

        //初始化
        xhr.open("GET","https://api.apiopen.top/getJoke");

        //发送
        xhr.send();

        //4.绑定时间,处理响应结果
        xhr.onreadystatechange = function(){
            //判断
            if(xhr.readyState === 4){
                //判断响应状态吗 200-299
                if(xhr.status >= 200 && xhr.status < 300){
                    //表示成功
                    console.log(xhr.response);
                }else{
                    //如果失败
                    console.log(xhr.status);
                }
            }
        }
    </script>

请求成功效果:
原生Ajax请求数据
请求失败结果:
原生Ajax请求数据
2. Promise进行封装Ajax代码

<script>
        //接口地址:https://api.apiopen.top/getJoke

        const p = new Promise((resolve,reject)=>{

        //创建对象
        const xhr = new XMLHttpRequest();

        //初始化
        xhr.open("GET","https://api.apiopen.top/getJoke");

        //发送
        xhr.send();

        //4.绑定时间,处理响应结果
        xhr.onreadystatechange = function(){
            //判断
            if(xhr.readyState === 4){
                //判断响应状态吗 200-299
                if(xhr.status >= 200 && xhr.status < 300){
                    //表示成功
                    resolve(xhr.response)
                }else{
                    //如果失败
                    reject(xhr.status);
                }
            }
        }
    });
    //指定回调
    p.then(
    function(value){
        console.log(value);
    },
    function(reason){
        console.log(reason);
    })
    </script>

成功效果:
Promise进行封装Ajax代码
失败效果:
Promise进行封装Ajax代码
处理方式不一样,原来是在回调函数里面处理成功和失败的结果,promise实在异步任务的后面通过then来指定回调,结构清晰,也不会产生回调地狱的问题。

es6-Promise.prototype.then方法

  1. then返回结果:返回结果是由执行函数的回调结果来决定的,如果回调函数中返回的结果是 ||promise类型的属性,状态为成功,返回值为对象的成功值。

  2. then返回非Promise对象

//创建promise对象
   const p = new Promise((resolve,reject)=>{
       setTimeout(()=>{
          //resolve("请求成功")
          reject("请求失败")
       },1000)
   });

   //调用 then方法
   const result = p.then(value =>{
       console.log(value);
       return value;
   },reason =>{
       console.log(reason);
       return reason;
   })
   console.log(result);

Promise.prototype.then方法返回结果
Promise.prototype.then方法返回结果
不写return返回undefined结果:
Promise.prototype.then方法返回结果
3. then返回Promise对象
then返回Promise对象,then中promise的状态就决定了then方法返回的一个对象的状态,then中Promise的失败就决定了then方法返回的一个失败的状态。

//创建promise对象
   const p = new Promise((resolve,reject)=>{
       setTimeout(()=>{
          resolve("请求成功")
          //reject("请求失败")
       },1000)
   });

   //调用 then方法
   const result = p.then(value =>{
       return new Promise((resolve,reject)=>{
           resolve('ok')
       })
   },reason =>{
       console.log(reason);
   })
   console.log(result);

then返回Promise对象
then返回Promise对象
4. then抛出错误
【如果抛出错误的话,这个状态也是一个失败的Promise状态,错误的值就是抛出的值】

//创建promise对象
   const p = new Promise((resolve,reject)=>{
       setTimeout(()=>{
          resolve("请求成功")
          //reject("请求失败")
       },1000)
   });

   //调用 then方法
   const result = p.then(value =>{
       //抛出错误
       throw new Error("出错啦")
   },reason =>{
       console.log(reason);
   })
   console.log(result);

效果:
then抛出错误
既然then的方法可以返回promise对象,所以说then方法可以链式调用,链式调用[then方法指定回调的时候是可以只指定一个的,可以通过链式调用来改变回调地狱的问题]
格式:

p.then(value=>{
    //异步任务
},reason=>{
 //异步任务
}).then(value=>{
     //异步任务
},reason=>{
 //异步任务
})

es6-promise实践练习-多个文件内容读取

        //回调地狱容易重名,很不容易被发现
  1. 使用回调地狱方式来做
//引入fs模块
const fs = require("fs")

fs.readFile('./resources/1.md',(err,data)=>{
    fs.readFile('./resources/2.md',(err,data1)=>{
        fs.readFile('./resources/3.md',(err,data2)=>{
            let result = data+"\r\n"+data1+"\r\n"+data2
            console.log(result);
        });
    });
});

上面代码可以发现 ,回调地狱容易重名,很不容易被发现。
Promise实现:

//使用promise来实现
const p = new Promise((resolve,reject)=>{
    fs.readFile("./resources/1.md",(err,data)=>{
        resolve(data);
    })
})
p.then(value=>{
    return new Promise((resolve,reject)=>{
        fs.readFile("./resources/2.md",(err,data)=>{
            resolve([value,data]);
        });
    });
}).then(value=>{
    return new Promise((resolve,reject)=>{
        fs.readFile("./resources/3.md",(err,data)=>{
            //压入
            value.push(data);
            resolve(value)
        });
    });
}).then(value=>{
    console.log(value.join('\r\n'));
})

promise实现多个文件内容读取

es6-Promise对象catch方法

catch用来指定promise失败的一个回调

第一种方式代码:

 <script>
        const p = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                //设置p对象的状态为失败,并且设置失败的值
                reject("出错啦")
            })
        })
        p.then(function(value){

        },function(reason){
            console.error(reason);
        })
    </script>

效果:
Promise中的catch方法

第二种方式代码:

<script>
        const p = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                //设置p对象的状态为失败,并且设置失败的值
                reject("出错啦")
            })
        })
        p.catch(function(reason){
            console.warn(reason);
        })
    </script>

Promise中的catch方法

es6-集合介绍与API

set介绍

ES6提供了新的数据结构Set(集合)。它类似于数组,但成员的值都是唯一的集合实现了iterator接口,所以可以使用[扩展运算符]和[for…of…]进行遍历

集合的属性和方法:
1)size: 返回集合的元素个数
2)add: 郑加一个新元素,返回当前集合
3)delete: 删除元素,返回boolean值
4)has:检测集合中是否包含某个元素,返回boolean值

简单通过代码了解Set:

   //声明一个set
    let s = new Set();
    //可以写入可迭代数据,可以去重
    let s2 = new Set(['大事儿','小事儿','坏事儿','小事儿','很多事儿','大事儿'])
    console.log(s,typeof s);
    console.log(s2);

效果:
es6-集合介绍与API
集合属性和方法的介绍代码和效果

 //元素个数
    let s2 = new Set(['大事儿','小事儿','坏事儿','小事儿','很多事儿','大事儿'])
    console.log(s2.size);
    //向集合里添加新的元素
    s2.add("喜事儿")
    console.log("集合添加后有:"+s2.size+"个",s2);
    //删除元素
    s2.delete("坏事儿")
    console.log("集合删除后有:"+s2.size+"个",s2);
    //检测【检测集合中有没有该元素】
    console.log(s2.has('喜事儿'));
    //可以使用for...of...遍历
    for(let v of s2){
        console.log(v);
    }
    //清空集合
    s2.clear();
    console.log(s2);

效果:
es6-集合介绍与API

es6-集合实践

已经知道两个数组:

let arr = [1,2,3,4,5,4,3,2,1,5,4,5,8,9,54,4,1]
let arr2 = [54,1,3,4,6,9,8]
  1. 数组去重
 //1.数组去重
        let result = [...new Set(arr)]
        console.log(result);

使用setApi进行数组去重
2. 两个数组求交集

//2.交集
    let arr2 = [54,1,3,4,6,9,8]
        let result2 = [...new Set(arr)].filter(item=>{
            let s2 = new Set(arr2)
            if(s2.has(item)){
                return true
            }else{
                return false
            }
        })
    console.log(result2);
    //简化版求交集
    let result3 =[...new Set(arr)].filter(item=>new Set(arr2).has(item))
    console.log(result3);

使用Set的API求数组的交集
3. 两个数组求并集

//3.并集
        let result4 =[...new Set([...arr,...arr2])]
        console.log(result4);

效果:
使用setAPI求两个数组的并集并且去重
4. 求两个数组的差集【交集的逆运算】

//4.差集
        let result5 = [...new Set(arr)].filter(item=>{
            let s2 = new Set(arr2)
            if(!s2.has(item)){
                return true
            }else{
                return false
            }
        })
      let result6 =[...new Set(arr)].filter(item=>!new Set(arr2).has(item))
    console.log(result5);
    console.log(result6);

效果:利用Set的API求两个数组的差集

es6-Map的介绍与API

es6提供了map数据结构,它类似于对象,也是键值对的集合,但是"键"的范围不限于字符串,各种类型的值(包括对象)都可以当做键,map也实现了iterator接口,所以可以使用【扩展运算符】和【for…of…】进行遍历,map的属性和方法:

  1. size 返回map的元素个数
  2. size 正价一个新元素,返回当前的map
  3. get 返回键名对象的键值
  4. has 检测map中是否包含某个元素,返回bollean值
  5. clear 清空集合,返回undefined
    声明一个Map并且添加
 //声明 Map
    let m = new Map();

    //添加元素
    m.set('name','吴又可');
    m.set('change',function(){
        console.log("无用的方法");
    });
    console.log(m);

MapAPI
map添加第二种方法

 //声明 Map
    let m = new Map();

    //添加元素
    m.set('name','吴又可');
    m.set('change',function(){
        console.log("无用的方法");
    });
    let key = {
        school : "sgg"
    };
    m.set(key,['北京','上海','广州']);
    console.log(m);

效果:
map API
map的其他API

//添加
    m.set(key,['北京','上海','广州']);
    
    //删除
    m.delete('name')
    console.log(m);

    //获取
    console.log(m.get('change'));
    console.log(m.get(key));

    //遍历
    for(let v of m){
        console.log(v);
    }

    //清空  
    m.clear();

Map的其他API

es6-class类

es6提供了更接近传统语言的写法,引入了Class类这个概念,作为对象的模板,通过class关键字,可以定义类,基本上,es6的class可以看做只是一个语法糖,它的绝大部分功能,es5都可以做到,新的class写法只是让对象的圆形的写法更加清晰,更像面向对象编程的语法而已。

  1. 知识点:
    (1) class声明类
    (2) constructor定义构造函数初始化
    (3) extends继承父类
    (4) static定义静态方法和属性
    (5) super调用父级构造方法
    (6) 父类方法可以重写

  2. 回顾Es6类的使用

 // 手机
    function Phone(brand,price){
        this.brand = brand;
        this.price = price;
    }

    //添加方法
    Phone.prototype.call = function(){
        console.log("我可以打电话");
    }

    //实例化对象
    let Huawei = new Phone('华为',5999);
    Huawei.call();
    console.log(Huawei);

使用效果:
es5class的使用
3. es6的class的使用

// class
    class Phone{
        //构造方法,名字不能修改,当实例化的时候会自动执行
        constructor(brand,price){
            this.brand = brand;
            this.price = price;
        }

        //方法必须使用该语法,不能使用es5的对象完整形式
        call(){
            console.log("我可以打电话");
        }
    }
    let onePlus = new Phone("huawei",4999);
    console.log(onePlus);

es6的class使用效果
es6的class使用效果

es6中Class里面的静态成员

es5中的静态成员

es5中实例对象和函数对象的属性是不相通的,实例对象的属性和构造函数的原型对象相通,实例对象的隐式原型指向构造函数的原型对象

 function Phone(){

    }
    Phone.name = "手机";
    Phone.change = function(){
        console.log("我可以改变世界");
    }
    Phone.prototype.size = "5.5inch"
    let nokia = new Phone();
    console.log(nokia.name);
    console.log(nokia.size);
    npkia.change();

效果:
es5的静态变量

未完待续~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值