前端笔记-js

本文详细讲解了JavaScript的基础数据类型、变量定义、运算符逻辑、函数使用、new关键字、数据类型判断、计时器、JSON、DOM操作、网络请求以及ES6新增特性。深入理解变量作用域、函数回调、构造函数和本地存储等内容。

html-js

上次笔记记录了css的基本内容,下面的笔记是记录js的基础内容。
js在我理解就是实现功能的(当然,他什么都能干),当我们用css画出了我们想要的界面以后,就要用js来完善我们的功能,一个没有功能的网页是没有灵魂的。(因为是笔记,所以顺序是乱的,大家可以跳着看)

js基础

数据类型

js中有六种数据类型,包括五种基本数据类型和一种复杂数据类型。
基本数据类型:

  1. 数字型(js中不分整数和小数):number

  2. 字符串:string 字符串的3种表示方法: “” , ‘’ , ``

    备注: 单引号 和 双引号 一样,只能写一行,不能分行写 , `` 可以分行写

  3. Boolean类型:只有true and false

  4. Undefined类型:只有一个值 Undefined

  5. Null类型: null类型被看做空对象指针,前文说到null类型也是空的对象引用。
    复杂数据类型:

  6. Object类型:我们看到的大多数类型值都是Object类型的实例,创建Object实例的方式有两种。
    第一种是使用new操作符后跟Object构造函数,如下所示

    var ren= new Object();
    ren.name = "Micheal";
    ren.age = 24;
    

    第二种方式是使用对象字面量表示法,如下所示

    var ren= {
    	name : "Micheal",
    	age : 24};
    

    可以给任意对象增加任意新的属性值

    ren. score = 90
    console.log(ren.score) //90
    
  7. Array类型
    数组的每一项可以用来保存任何类型的数据,也就是说,可以用数组的第一个位置来保存字符串,第二个位置保存数值,第三个位置保存对象…另外,数组的大小是可以动态调整的。

    创建数组的基本方式有两种

    • 第一种是使用Array构造函数,如下所示

      var colors = new Array("red","blue","yellow");

    • 第二种是使用数组字面量表示法,如下所示
      var colors = ["red","blue","yellow"];

  8. Function类型
    每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。函数通常是使用函数声明语法定义的,如下所示

    function sum(num1,num2){
    	return num1 + num2;
    };
    //这和使用函数表达式定义函数的方式相差无几。
    var sun = function (){
    	return sum1 + sum2;
    };
    
  9. 数据之间机算问题:

    var a = 100; //unmber 
    var b = '10' //string
    var c = a+b
    console.log(c)  //10010 字符串+数字 默认按照字符串拼接
    var d = a - b 
    console.log(d)  //90 数字-字符串 默认把字符串转换为数字机算
    console.log(a-'b') //NaN 如果字符串不能转换为数字 那么结果就是NaN类型 NaN类型不等于任何值,包括自己
    

变量的定义和使用

变量:程序运行期间能够被改变的量称为变量

  1. 先定义

    • 使用var关键字来定义变量 具有声明前置
    • 使用let关键字来定义变量 不具有声明前置 可能会引起局部性死区
    • 使用const关键字来定义常量 不具有声明前置 定义后不能修改
  2. 后使用
    不需要写var关键字,直接使用变量名称使用
    变量:使用的是变量中的内容
    变量:本质是容器
    容器:是用来装内容的同一时间,只能装一个内容

  3. 变量的命名规范
    变量:名称可以随便定义,但是也有一定的规则
    - 不能与系统关键字重名
    - 只能由字母数字和下划线_组成,并且不能以数字开头
    - 变量要采用下划线分割法或驼峰命名法
    - 变量尽量不用采用拼音
    - js中 $能当变量名
    注意:变量要做到见名知意

  4. var声明注意事项
    1.var a = 9
    将 a 声明成 window 的一个属性

    2.如果在函数内部使用var a = 9
    要注意变量声明前置的问题
    var a = 9
    (var a; //上去 a = 9 //还在原来的位置)
    (前置到当前作用域的最上方)

    3.var a;
    当一个变量被定义,并且没有被初始化
    默认就是undefined

    4.function内部的 a 和外部 a 同时使用 此时在function中使用 Windows.a

运算符

  1. =:赋值符号
    右侧的结果给左侧的变量

  2. +=++
    a=a+9可简写为a+=9
    a = a+1可简写为a+=1a++++a
    a++++a
    ++在前,先进行运算,再进行使用
    ++在后,先进行使用,在进行自增

  3. 注意事项
    求和:左右都是数字
    拼接:左右有一个是字符串

  4. 减号注意事项
    -:左右都会转成数字
    一旦转化不成功,就得到NaN
    NaN:不等于任何东西(包括自己)

  5. 条件运算符
    > < >= <= == !== ===
    备注:
    ==:只判断值
    ===:不仅判值,还判断类型

  6. bool类型
    bool: true false
    有且只有这二个值

  7. 逻辑运算符
    &&||!
    非:取反
    与:两个都为真才是真
    或:有一个为真即为真
    短路现象:
    true || 短路
    false && 短路
    补充
    1. 在判断语句的判断条件中:非0即真
    数字0"" 翻译成false
    2. truefalse在参与求和运算的时候
    会转化成10
    在参与拼接的时候
    会转化成"true""false"

  8. { } 功能:

    1. 封闭作用域
    2. 代码结构
    3. 作用域
  9. ( ):
    放表达式:变量 常量 或 运算符

逻辑运算

  1. if(判断条件){}

    • 判断条件:只要是表达式就行
    • ture false 其他
    • 其他:
      数字:非0即真
      字符串:非空即真
      undefined,null --> false
  2. for(循环条件){ } //使用场景:有确定次数的时候
    循环条件:能够让循环因子持续不停发生改变的
    1.必须有循环因子
    2.必须让循环因子改变
    3.必须确定(可触)阈值

    for (var i = 0; i< 10;i++){
    	console.log(i)
    }
    
  3. while(循环条件){} //使用场景:有确定点的时候

    var a = 9
    while (a< 15){
    	console.log(a)
    	a++
    }
    
  4. for(key in 循环对象){} //使用场景:遍历对象中所有属性的时候

    for (var key in ren) {
    	console.log(ren[key])
    }
    
  5. 循环中的两个关键字
    continue:结束本次循环
    break:结束本轮循环

函数的使用

  1. 定义函数——函数的声明

    • 声明式函数定义:
      function xxx(){ *** }
    • 赋值式函数定义
      var yyy = function () { *** }
    • 构造函数方式定义
      var xxx= new Function() { *** };
  2. 使用函数 函数的调用
    切记:函数一旦调用,必然触发 函数声明时候的 执行体的 执行

  3. 没有名称的函数称为匿名函数
    匿名函数必须立即调用,不然,就不能调用了
    (function () { *** }())

  4. 函数的名称也是变量,也可以被重新赋值的

    function xxx(){}
    xxx = 9
    console.log(xxx) //9
    xxx() //报错,因为xxx里面已经不再是一个函数了
    
  5. 函数中的this
    this :谁调用谁就是this
    切记:定时器中的this 永远代表的是 window
    因为只有window有能力启动并触发定时器中的函数
    改变函数中的this,三个办法(将函数中的 this 换成老王)

    1. 函数.call(老王)
    2. 函数.apply(老王)
    3. 函数.bind(老王)
  6. return:

    1. 必须在函数中出现
    2. 代表的是函数的结果返回值
      切记:return后面是什么,函数的结果就是什么
      反之,如果没有return ,或return后面没东西,
      那么函数的返回值就是undefined
    3. 提前结束函数
  7. 参数
    function(参数){}

    1. 实参 和 形参(可以随便起名)
      形参:定义函数的时候
      (参数)称为:形参
      实参:调用函数的时候
      (参数)称为:实参
    2. 实参 到 形参的 传递过程
      是一个 值 拷贝的 过程
      深拷贝 浅拷贝
      深拷贝:内容拷贝传递过去 eg:传递一个数字 字符串 数组中的某个值
      浅拷贝:地址拷贝传递过去 eg:传递数组,对象等需要new创建的
  8. 函数的回调

    1. 把函数当成参数
    2. 把参数进行函数调用
  9. 构造函数(这个好好看)

    1. 每一个函数都有两个作用
      1. 用来被调用
      2. 用来被创建对象
    2. 当一个函数被用来创建对象的时候,此时,我们称该函数为构造函数
    3. 构造函数首字母一般大写
    4. var a = new函数名();// 用函数来new对象
    5. 函数的原型:函数. prototype
      对象的原型:对象.__proto__
    6. 在构造函数的原型上增加新东西,
      就可以让该函数所创建的对象进行使用
    Array.prototype.run = function(){
    	console.log(“我会跑步了...")
    }
    var a =[1 , 2 , 5]
    a.run()
    

new关键字

  1. new 只能出现在函数名称前面

  2. 由new关键字创建出的对象有3个能力
    1. Object {}
    2. Person
    3. this

  3. new关键自己的原理
    new:步骤
    1.创建一个新对象 {}
    2.xxx.call({})
    3.{}.proto = Xxx.prototype

    eg:

    var a = 0
    a.__proto_ = Person. prototype
    Person.call(a)
    
    var b = new Person()
    

    两种是一样的

  4. 用来生成新对象
    构造函数:用来创建对象的函数称为 构造函数
    构造函数默认:首字母大写

    function Xxx(){
    	this.name = "zhangsan"
    	var a = 111
    	}
    xxx() //函数的调用 
    new xxx() //函数对象的创建
    
  5. 字面量写法

    //创建数字变量
    var c = new Number(8)
    var c = 8
    //创建对象
    var b = new Object({})
    var b = {}
    //创建数组
    var a = [1 ,2 , 8 , 9]
    var a = new Array(1 , 2 ,8 , 9)
    

判断数据类型:

  • typeof 用于判断未知数据类型 结果为 number string function object
  • instanceof 用于判断数据已知数据类型 结果为 true or false
    eg:
    var a = new String("asdas") //true
    console.log(a instanceof String)    //true
    console.log(4354 instanceof Number) //false 只有使用 new 方法实例化的变量才能
    
  • instanceof
    console.log([1,5,4] instanceof Array) //true 用于判断object类型数据是数组还是对象
    
  • toString 最全面的判断数据类型的方法
    eg:
    toString.call(数据) 
    //结果为 [object , Object] 
    //后面的为数据类型,首字母大写
    

计时器

  1. 循环计时器
setInterval(function (){
	//执行内容
},1000) //解释:每个1000毫秒,执行一次函数
  1. 延迟计时器
setTimeout(function (){
   //执行内容
},1000) //解释:每个1000毫秒,执行一次函数
  1. 清除循环定时器 clearInterval(aaa)

json字符串

  1. 说明
    把符合对象,数组或他们嵌套格式的字符串,称之为json字符串
    切记:json字符串中的属性要带 " "
    eg::'{"age":12}'
  2. json字符串解析 toString() //字符串化
    var bbb = JSON.parse('json字符串')
    把json字符串 解析成 对象 或者 数组
  3. json字符串化:
    JSON.stringify()
    把数组或对象转换为json字符串

DOM [document object model]操作

DOM中的节点
  1. 元素节点
  2. 文本节点
  3. 声明节点
  4. 注释节点
  5. 文档根节点
DOM中的特殊节点
  1. 根节点 document
  2. 声明节点document.doctype
  3. head document.head
  4. body document.body
  5. html document.documentElement
获取元素中的节点

E.childNodes
E.firstChild
E.lastChild
E.parentNode
E.previoussibling
E.nextSibling
同理:都会对应一个元素节点的

获取界面上的DOM元素
  1. document.getElementsByClassName("one") //通过类名获取,得到的是个装着元素的数组
  2. document.getElementById("one") //通过id获取,得到的是匹配到的元素
  3. document.querySelector(".one") // 得到的是第一个匹配到的元素
  4. document.querySelectorAll(".two") // 得到的是所以匹配到的元素(数组)
    … …
    其他的方式同上
获取输入框中的内容

input= document.querySelector(".input_class_name")
input.value

给元素绑定监听事件

事件: 肯定 需要监听
只要是监听: 肯定是 on

  • 给元素增加点击事件
    1. 直接在标签上写 onclick="xxx()"
    2. 脚本中
      E.onclick=xxx
      E.onclick=yyy
      //只有yyy管用
      //原因:赋值符合有覆盖的作用
      
    3. 脚本中
      E.addEventListener("click",xxx)
      E.addEventListener("click",yyy)
      //xxx 和 yyy 都管用
      
  • 给元素增加键盘事件
    同样是三种方式,同上
     元素.onkeydown = function () {}}
    
修改元素的样式
  1. 样式的修改
    元素.style.样式 left, top
    eg:
    E.style.backgroundColor = "red"
    E.style.width = "100px"
    getComputedstyle(参数1,,参数2)
    //参数1:元素
    //参数2:伪元素选择器//如果参数2为null,或没有,获取元素的所有样式
    //如果参数2位伪元素选择器,获取的是伪元素选择器里面内容的所有样式
    
  2. 内容的修改
    元素.innerHTML
    元素.innerText
    元素.value
  3. 元素宽高获取:
    元素.offsetWidth
    元素.clilentWidth
  4. 特有属性的修改
    元素.src =
  5. 关系的修改和访问
    元素.append(小元素)
    元素.innerHTML = “”
    元素.childRen
    元素.previousElementSibling
    元素.nextElementSibling
    元素.parent…
  6. 删除元素:
    元素.innerHTML = “” // 删除自己内部的
    元素.remove() // 删除自己
  7. 通过js创建元素
    document.createElement(“div”)
元素的尺寸
E.clientwidth = padding-left + content-width + padding-right
E.clientHeight 同理
E.clientTop = border-top
E.clientLeft同理
E.offsetwidth = clientwidth + border-left + border-right
E.offsetHeight同理
E.offsetParent:离自己最近的具有定位属性的父辈元素,祖宗是body
E.offsetTop:自身上边框外框到offsetParent的上边框的内边框距离
E.offsetLeft同理
元素的scrollHeight 滚动尺寸:
if子元素的高度> content.height:
	自己.scrollHeight =子元素.offsetHeight +自己.padding-top+自己
else:
	自己.scrollHeight =自己.clientHeight
	元素的scrollwidth 滚动尺寸:同理

脚本(js)与界面之间的关系

window窗口= document文档(内部有元素) +js(语法基础)

  1. js 想从界面中获取元素
    var a = document.getElementsByClassName("标签的类名")[0]
    变量a就是这个元素了,但同时a又具有了js 对象的特征
  2. 用js获取界面上元素的过程,我们称之为DOM 获取
    DOM : docuemt object model(文档对象模型)

ajax网络请求

通过接口访问服务器,服务器访问数据库,将获取到的数据返回给脚本,脚本在讲数据展示在界面上

var req = new XMLHttpRequest()
req.open("GET", url , true)
req.send()
req.onreadystatechange = function(){
	if (req.readyState == 4 && req.status == 200){
		var bbb = JSON.parse(req.responseText) //获取到请求结果
	}   
}

备注:获取到的请求结果是:req.responseText
但一般获取到的请求结果都是字符串,所以我们需要将结果
进行一个json解析,方便我们使用请求到的数据

typeof面试题

  1. typeof :
    即是操作符---->typeof a
    也是函数---->typeof(a)
  2. 大于等于2个typeof时,其结果必然是string
    console.log(typeof typeof a) // string
    console.log(typeof(typeof(a)) // string

本地存储(浏览器缓存)

localStorage.getItem("name") //获取缓存
localStorage.setItem("name","data") //存储到缓存中
因为本地缓存只能存储字符串数据,所以存储数据之前要进行:
JSON.stringify() //即将数组,对象化为json字符串
读取本地缓存之后要进行:
JSON.parse() // 解析 (必须是json字符串)

ES6补充学习

  1. let: (类似var声明)
    1.作用域 —> 块级作用域 —>{}
    2.不能形成变量声明前置
    //暂时性死区-整个作用域中 不能被访问的那段 (暂时性死区不允许任何人动let 声明的变量 比如typeof )
    3.同一个作用域 不能重名
    4.在嵌套作用域可以重复声明

  2. const
    常量
    定义常量后,不可修改,且定义常量时必须要初始化(即定义时就要赋值)
    const 与 let一样都是块级声明

  3. 字符串与正则表达式
    repeat()
    它接受⼀个参数作为字符串的重复次数,返回 ⼀个将初
    始字符串重复指定次数的新字符串

  4. 函数

    1. 默认参数
      1.在 ES5 或更早的版本中
      你可能会使⽤下述模式来创建带有参数默认值的函数:

      function makeRequest(url, timeout, callback) {
      timeout = timeout || 2000;
      callback = callback || function() {
      //函数剩余部分
      };}
      

      不过此⽅法有个瑕疵,此处的timeout的有效值实际上有可能是0,但因为0是假值,就会导致timeout的值在这种情况下会被替换为2000.在这种情况下,更安全的替代⽅法是使⽤ typeof 来检测参数的类型,正如下例:

              function makeRequest(url, timeout, callback) {
              timeout = (typeof timeout !== "undefined") ? 
              timeout : 2000;
              callback = (typeof callback !== "undefined") ? 
              callback : function() {
                  //函数剩余部分
              };}
      

      虽然这种⽅法更安全,但依然为实现⼀个基本需求⽽书写了过多的代码。它代表了⼀种公共模式,⽽流⾏的JS库中都充斥着类似的模式

    2. ES6 中的参数默认值

      function makeRequest(url, timeout = 2000, callback = function(){}){
      	//函数剩余部分
       }       
      
    3. 参数默认值如何影响 arguments 对象
      arguments 与 严格模式
      假设 一个函数有 两个参数 first , second.
      在非严格模式下
      firstarguments[0]相通
      secondarguments[1] 相通
      在 严格模式 “use strict” 下
      firstarguments[0] 不相通
      secondarguments[1] 不相通

      ES6 默认运行在 严格模式下

    4. 参数的默认值
      1. 参数可以有默认值
      2. 参数的默认值可以是表达式
      3. 参数的默认值的依赖顺序: 只能是 后面的 依赖 前面的
      4. 参数默认值表达式

      参数默认值最有意思的特性或许就是默认值并不要求⼀定是基本类型的值。例如,你可以执⾏⼀个函数来产⽣参数的默认值,此处若未提供第⼆个参数,getValue()函数就会被调⽤以获取正确的默认值。需要注意的是,仅在调⽤add()函数⽽未提供第⼆个参数时,getValue()函数才会被调⽤,⽽在getValue()的函数声明初次被解析时并不会进⾏调⽤。这意味着getValue() 函数若被写为 可变的,则它有可能会返回可变的值,这种⾏为引出了另⼀种有趣的能⼒:可以将前⾯的参数作为后⾯参数的默认值,
      这⾥有个例⼦:

                  function add(first, second = first) {
                      return first + second;
                  }
                  console.log(add(1, 1)); // 2
                  console.log(add(1)); // 2
      

      此代码中firstsecond参数提供了默认值,意味着只传⼊⼀个参数会让两个参数获得相同的值,因此add(1,1)与add(1)同样返回了2。进⼀步说,你可以将first作为参数传递给⼀个函数来产⽣second参数的值,正如下例:

       function getValue(value) {
      	return value + 5;
       }
       function add(first, second = getValue(first)) {
          return first + second;
       }
       console.log(add(1, 1)); // 2
       console.log(add(1)); // 7
      

      引⽤其他参数来为参数进⾏默认赋值时,仅允许引⽤前⽅的参数,因此前⾯的参数不能访问后⾯的参数,例如:

      	function add(first = second, second) {
      		return first + second;
      	}
      	console.log(add(1, 1)); // 2 
         	console.log(add(undefined, 1)); // 抛出错误
      

      调⽤ add(undefined, 1) 发⽣了错误,是因为 second 在first 之后定义,因此不能将其作 为后者的默认值。要理解为何会发⽣这种情况,需要着重回顾“暂时性死区”

  5. 剩余参数

    1. 剩余参数( rest parameter )由三个点( … )与⼀个紧跟着的具名参数指定,它会是包 含传递给函数的其余参数的⼀个数组,名称中的“剩余”也由此⽽来:

      function pick(object, ...keys) {
      	let result = Object.create(null);
      	for (let i = 0, len = keys.length; i < len; i++) {
      		result[keys[i]] = object[keys[i]];
      	}
      	return result;
      }
      //函数的length属性⽤于指示具名参数的数量,⽽剩余参数对其毫⽆影响。
      //此例中pick()函数的length属性值是1,因为只有object参数被⽤于计算该值。
      
    2. 剩余参数的限制条件
      ⼀是函数只能有⼀个剩余参数,并且它必须被放在最后
      第⼆个限制是剩余参数不能在对象字⾯量的setter属性中使⽤,这意味着如下代码同样会导致语法错误:

      let object = {
          // 语法错误:不能在 setter 中使⽤剩余参数
          set name(...value) {
            // ⼀些操作
          }
        };
      

      存在此限制的原因是:对象字⾯量的setter被限定只能使⽤单个参数;⽽剩余参数按照定义是不限制参数数量的,因此它在此处不被许可

    3. 剩余参数如何影响 arguments 对象
      arguments对象在函数被调⽤时反映了传⼊的参数,与剩余参数能协同⼯作,就像如下程序所演示的:

        function checkArgs(...args) {
          console.log(args.length); //2
          console.log(arguments.length); //2
          console.log(args[0], arguments[0]); //a a 
          console.log(args[1], arguments[1]); //b b 
        }
        checkArgs("a", "b");
      

      arguments 对象总能正确反映被传⼊函数的参数,⽽⽆视剩余参数的使⽤

    4. 扩展运算符
      与剩余参数关联最密切的就是扩展运算符。剩余参数允许你把多个独⽴的参数合并到⼀个数组中;⽽扩展运算符则允许将⼀个数组分割,并将各个项作为分离的参数传给函数。

        let value1 = 25,
          value2 = 50;
        console.log(Math.max(value1, value2)); // 50
      

      若像本例这样仅处理两个值,那么 Math.max() ⾮常容易使⽤:将这两个值传⼊,就会返回较⼤的那个。但若想处理数组中的值,此时该如何找到最⼤值?
      因为Math.max() ⽅法并不允许 你传⼊⼀个数组在 ES5 或更早版本中,你必须⾃⾏搜索整个数组,或像下⾯这样使⽤apply() ⽅法:

        let values = [25, 50, 75, 100]
        console.log(Math.max.apply(Math, values)); // 100
      

      该解决⽅案是可⾏的,但如此使⽤ apply() 会让⼈有⼀点疑惑,它实际上使⽤了额外的语法 混淆了代码的真实意图
      ES6 的扩展运算符令这种情况变得简单⽆须调⽤ apply() ,你可以像使⽤剩余参数那样在 该数组前添加 … ,并直接将其传递给 Math.max()。JS 引擎将会将该数组分割为独⽴参 数并把它们传递进去,就像这样:

      let values = [25, 50, 75, 100]
        // 等价于 
      console.log(Math.max(25, 50, 75, 100)); 
      console.log(Math.max(...values)); // 100
      

      你可以将扩展运算符与其他参数混⽤。假设你想让Math.max() 返回的最⼩值为 0 (以防数 组中混⼊了负值),你可以将参数 0 单独传⼊,并继续为其他参数使⽤扩展运算符,正如下 例:

        let values = [-25, -50, -75, -100]
        console.log(Math.max(...values, 0)); // 0
      

      本例中传给Math.max()的最后⼀个参数是0,它跟在使⽤扩展运算符的其他参数之后传⼊。⽤扩展运算符传递参数,使得更容易将数组作为函数参数来使⽤,你会发现在⼤部分场景中 扩展运算符都是apply() ⽅法的合适替代品。
      除了你⾄今看到的默认参数与剩余参数的⽤法之外,在ES6中还可以在JS的Function构造器中使⽤这两类参数

  6. 函数构造器的增强能⼒
    Function 构造器允许你动态创建⼀个新函数,但在JS中并不常⽤。传给该构造器的参数都是字符串,它们就是⽬标函数的参数与函数体

    	  var add = new Function("first", "second", "return first + second");
    	  console.log(add(1, 1)); // 2
    

    ES6 增强了 Function 构造器的能⼒,允许使⽤默认参数以及剩余参数。
    使⽤默认参数: 你只需为参数名称添加等于符号以及默认值

      var add = new Function("first", "second = first",
        "return first + second");
      console.log(add(1, 1)); // 2
      console.log(add(1)); // 2
    

    使⽤剩余参数: 只需在最后⼀个参数前添加 … 即可

      var pickFirst = new Function("...args", "return args[0]");
      console.log(pickFirst(1, 2)); // 1  
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值