js --- 完整知识体系

JavaScript初识

1、组成
  • BOM:JS操作 “浏览器” 发生变化的属性和方法
  • DOM:JS操作 “文档流” 发生变化的属性和方法
  • ECMAScript:JS的语法和标准
2、JavaScript的数据类型
  • 基本数据类型:Number、String、Boolean(true/false)、Undefined、Null
  • 引用数据类型:Object、Function、Array
  • 数据存储的区别:
    • 栈内存:基本数据类型,直接把值存在栈内存里面
    • 堆内存:引用数据类型,将地址存在栈内存,数据存在堆内存里面
  • 检测基本数据类型:typeof
3、JavaScript的数据类型转换
  • 转数值:Number(内容)、parseInt(内容)、parseFloat(内容)
  • 转字符串:String(内容)、内容.toString()
  • 转布尔:Boolean(内容) // 只有“ 0、NaN、空字符串(’ ') 、undefined、null ”转换为false

ES语法规范

1、关键字
  • 声明变量的关键字
    • var :es6以前声明变量,可以重复声明变量,不会报错
    • let : es6新增的关键字,用来取代var,比var的好处 有块级作用域
    • const :声明常量
  • 声明函数的关键字
    • function : 声明函数
  • 声明类的关键字
    • class : 声明类
2、运算符
  • 算数运算符: +、-、*、/、%(取余)、**(取幂)
  • 赋值运算符:=(赋值)、+=、-=、*=、/=、%=
  • 比较运算符:>、<、>=、<=、= =、= = =、!=、!==
  • 逻辑运算符:&&(与/且)、||(或)、!(取反)
  • 自增自减运算符:++、–
console.log(a++)  // 先使用 在运算
console.log(++a)  // 先运算 在使用
let h += a   // 相当于 h = h + a
a == b       // 比较值,不比较类型
a === b      // 全等 值和类型都有相等
a && b   // a是true 且 b也是true
a || b   // 如果a是true 直接返回true 如果a不是true 判断,b是true,也返回true, 否则返回false。
!a       // 取反
3、条件分支语句
  • if
if (条件) {
    /* 满足此条件执行的代码 */
} else if (条件) {
    /* 满足此条件执行的代码 */
} else {
    /* 以上条件都不满足 执行的代码 */
}
  • switch
switch (形参) {
    case 选项1:
        /* 形参 = 选项1 执行的代码 */ 
        break;
    case 选项2:
        /* 形参 = 选项2 执行的代码 */ 
        break;
    default:
        /* 以上都不满足 执行这里的代码 */
}
4、循环结构语句
  • for 循环
const arr = ['a', 'b', 'c']

// 满足几次 这个循环的代码就会执行几次
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]) // arr[i] 代表每一次的值。 这个循环转3圈,每一圈的值。
}
  • while 循环 和 do while 循环
 const arr = ['a', 'b', 'c']
       
// 和for循环差不多 只是写法不同 让我们多一种选择而已
let i = 0;
while (i < arr.length) {
    console.log(arr[i])
    i++
}

// 和while循环一样 只是先执行一次,再判断。
let i = 0;
do {
    console.log(arr[i])
    i++
} while (i < arr.length)
  • for in 循环
# 循环数组
const arr = ['a', 'b', 'c']
for (let index in arr) {
  console.log(index, arr[index])
}
# 注意:
1. 循环数组,index出来是 索引: 0 1 2
2. 取值的话,就是:  arr[0] arr[1] arr[2]

# 循环对象
const user = {
    name: '小貂蝉',
    age: 18,
    email: 'dc@qq.com'
}
for (let key in user) {
    console.log(key, user[key])
}
# 注意:
1. 循环对象,key是出来的键名:  name, age, email
2. 取值就是: user['name'] user['age'] user['email']
3. 对象取值,如果key是变量,必须使用 对象[key],不能 user.key
  • for of 循环
const arr = ['a', 'b', 'c']
for (let v of arr) {
    console.log(v)
}

# 注意:
1. 循环数组,出来的是: 每一项的值
2. 不能用来循环对象
5、循环控制语句
 循环控制语句  'break'
    + 当在一个循环里面执行到 break 关键字的时候
    + 会直接结束整个循环

 循环控制语句  'continue'
    + 使用在循环里面的关键字
    + 当代码执行到 continue 关键字的时候,会结束循环得本次,继续下一次

 循环控制语句  'JS 标记语法'
    + 直接在循环的开始位置做一个 标记
       名字:
    + 当你准备跳出的时候
       break 标记
       
    案例-------
        hrea:
        for (let i = 0; i < 9; i++) {
            for (let j = 0; j < 9; j++) {
                if (i === 3 && j === 5) {
                    console.log(111);
                    break hrea
                }
            }
            console.log(i);
        }
    ----------
6、三目运算
语法:
条件 ? 结果1 :结果2  //条件是true 走结果1  否则,走结果2
7、函数
  • 【1】声明式函数
function 函数名 (形参1,形参2){
    /* 代码块 */
}
  • 【2】函数表达式
const 变量 = function (形参1,形参2){
    /* 代码块 */
}
  • 【3】箭头函数
const 变量 = (形参1,形参2) => {
    /* 代码块 */
}

注意:
1.如果形参只有1个,可以省略()
2.如果{}只有1句代码,可以省略{},且必须省略return
3.箭头函数没有 arguments
4.箭头函数不能 new 
5.箭头函数的 this,指向上一级作用域
  • 【4】递归函数
概念:函数的一种应用方式
递:一层一层的进去
归:一层一层的回来       

本质:一个函数自己调用自己
    => 当达到设置的终点的时候
    => 再归回来,归使用 return
注意:** 写递归先写停 **

例:5的阶乘  5*4*3*2*1
    function fn(n) {
        if(n===1){
            //终点位置出现
            return 1
        }
        //递进去
        return n * fn(n-1)
     }
     let b = fn(5)
     console.log(b);
8、内置对象
Array
  • 属性
    • length:获取数组的长度
  • 方法
    reverse()    // 反转数组的顺序,作用:反转
    push()       // 在数组后面添加元素,作用:添加元素
    pop()        // 删除数组最后一个元素,作用:删除元素
    unshift()    // 前面添加一个元素,作用:添加元素
    shift()      // 前面删除一个元素,作用:删除元素
    join('连接符号')      // 数组转字符串,作用:转字符串
    indexOf()       // 查找元素所在的位置,作用:找元素索引
    lastIndexOf()   // 反向查看元素所在位置
    includes()   // 查看是否包含指定元素,作用:找元素
    flat(数字/Infinity)       // 降维 作用:多维数组,转1维数组 Infinity(无穷)
    splice(开始索引,删多少个,替换数据1,替换数据2...)     // 添加、删除、修改元素
    
    sort(function (a,b){ return a-b})  // 排序
    forEach(function (item,index) {})  // 循环,没有返回值
    map(function (item,index) {})      // 循环,把每次的结果,放入一个新数组,最后返回这个新数组
    filter(function (item,index) {})   // 过滤,把每一次满足条件的元素,放入一个新数组,返回这个新数组
    every(function (item,index) {})   // 每一个都满足,就返回true,否则,返回false
    some(function (item,index) {})    // 只要1个满足,就返回true,否则返回false
    findIndex(function (item) {})     // 找索引
    find(function (item) {})          // 找元素
    
    // 不改变原数组
    content()    // 连接两个或多个数组,作用:连接数组,合并数组
    slice()      // 切割数组,截取元素
    
String
  • 方法
    charAt(索引)           // 根据索引,查找字符
    charCodeAt(索引)       // 获取UTF-8编码
    concat('字符串')       // 拼接字符串
    includes('字符串')     // 查询是否包含
    indexOf('字符串')      // 查找字符的索引
    replace('要被替换的字符','替换成的字符')      // 替换
    slice(开始索引,结束索引)        // 截取
    split('切割符号')                // 字符串转数组
    substr(开始索引,多少个)         // 截取
    substring(开始索引,结束索引)    // 截取
    toLowerCase()        // 转小写
    toUpperCase()        // 转大写
    trim()               // 取两头空白
    search('字符串')     // 查找字符串里面有没有匹配的字符串片段
    
    // 不常用
    big() / small()    // 字体大/小
    bold()             // 加粗
    fontsize(尺寸)     // 字体大小
    fontcolor(颜色)    // 字体颜色
    
Date
  • 方法
    // 创建时间对象
    let time = new Date()   // 系统时间
    let time = new Date('年-月-日 时:分:秒')  // 创建指定日期
    
    // 获取时间对象信息的方法
    getFullYear()  // 获取年
    getMonth()     // 获取月 0~11
    getDate()      // 获取天 0~31
    getHours()     // 获取小时
    getMinutes()   // 获取分钟
    getSeconds()   // 获取秒
    getDay()       // 获取星期 0~6
    getTime()      // 获取 时间戳
    
Math
  • 方法
    Math.PI()       // 圆周率 3.1415926...
    Math.abs()      // 绝对值  |-10|->10
    Math.ceil()     // 向上取整
    Math.floor()    // 向下取整
    Math.max()      // 取最大值
    Math.min()      // 取最小值
    Math.random()   // 取随机数 0~1
    Math.round()    // 四舍五入
    
    Math.floor(Math.random()*(max-min+1)+min)   // 生成指定范围的随机整数
    
Number
  • 方法
    toFiexd(数值)   // 保留小数点位数
    
Object
  • 方法
    keys()     // 取出所有的key,放入一个数组
    assign()   // 合并多个对象
    
9、JSON格式
JSON.parse()         // 字符串 --> 数组/对象
JSON.stringify()     // 数组/对象  -->  字符串
10、本地存储
// 永久缓存(localStorage,只能手动删除)
localStorage.setTime('名字','值')  //  存储
localStorage.getTime('名字')       //  获取
localStorage.removeTime('名字')    //  删除指定数据
localStorage.clear()               //  清除所有数据

// 临时缓存(sessionStorage,关闭浏览器)
sessionStorage.setTime('名字','值')  //  存储
sessionStorage.getTime('名字')       //  获取
sessionStorage.removeTime('名字')    //  删除指定数据
sessionStorage.clear()               //  清除所有数据 

共同点:
    只能存储字符串格式的数据
    想存储对象数据结构,转换成json格式存储
11、定时器
// JS 的定时器
    setTimenout(函数,时间ms)   // 延时定时器
    setInterval(函数,时间ms)   // 间隔定时器
    
// 关闭定时器(不分定时器种类)
    clearTimeout()
    clearInterval()

JavaScript高级特性【es5】

1、作用域
  • 概念:标识符访问的"范围"。
  • 作用域链:从里往外,逐级向上查找,找到就使用,找不到就报错
  • 作用域分类:
    • 全局作用域(window)
    • 局部作用域(函数)
    • 块级作用域({})
2、闭包
  • 概念:函数跨作用域访问变量,形成闭包,闭包是一种作用域的体现
  • 写法:父函数嵌套子函数,子函数访问父函数的变量,把子函数返回或挂在全局
  • 作用:解决循环定时器问题,解决循环事件绑定问题,实现早期的模块化
  • 优缺点:优点是把变量隐藏在内部,避免全局污染。缺点是:过多使用闭包,变量常驻内存,不会被释放,造成内存开销过大,甚至内存泄漏。
3、原型
  • 概念
    • 【1】每个函数都有一个属性prototype,就是原型【显示原型】
    • 【2】添加在原型上的属性和方法,被所有实例对象共享
    • 【3】实例对象都有一个属性__proto__,指向构造函数的prototype
    • 【4】原型prototype上有一个属性constructor, 指向构造函数本身。
  • 作用
    • 添加共享方法
4、原型链
  • 概念
    • 【1】原型prototype本身也是实例对象,也有__proto__, 指向Object的prototype
    • 【2】Object.prototype也是实例对象,也有__proto__, 指向null
    • Object.prototype也有属性constructor,指向构造函数本身。
  • 作用
    • 添加共享方法
5、this
  • 7种指向
    • 全局 -> window
    • 函数 -> 调用者
    • 对象方法 -> 调用者
    • 构造函数 -> 实例对象
    • 事件绑定 -> 事件源
    • 定时器 -> window
    • 箭头函数 -> 上一级
  • 改变指向方法
    • call()
    函数.call(this的指向目标,参数1,参数2)
    
    • apply()
    函数.apply(this的指向目标,[参数1,参数2])
    
    • bind()
    let 新函数 = 函数.bind(this的指向目标)
    
    # 注意
    当我们调用新函数,新函数中的this,就永远指向之前绑定的 目标
    
6、类型检测
  • typeof 检测基本类型
    typeof 'abc'  // string
    typeof true   // boolean
    typeof 10     // number
    typeof undefined   // undefined
    typeof function(){}  // function
    typeof Symbol()   //symbol
    
    typeof null  // object
    typeof {}    // object
    typeof []    // object
    
  • instanceof 检测引用类型
    [] instanceof Array   // true
    {} instanceof Object  // true
    new Date() instanceof Data  // true
    
  • Object.prototype.toString.call() 检测所有类型
    Object.prototype.toString.call('abc')    // [Object String]
    Object.prototype.toString.call(10)       // [Object Number]
    Object.prototype.toString.call(true)     // [Object Boolean]
    Object.prototype.toString.call(undefined)  // [Object Undefined]
    Object.prototype.toString.call(null)       // [Object Null]
    Object.prototype.toString.call(Symbol())   // [Object Symbol]
    Object.prototype.toString.call(function () {})  // [Object Function]
    Object.prototype.toString.call([])     // [Object Array]
    Object.prototype.toString.call({})     // [Object Object]
    
  • Array.isArray() 检测是否是数组
7、深拷贝&浅拷贝
  • 浅拷贝
    • for in 循环
    let 对象1 ={
        属性名:属性值
        ...
    }
    let 对象2 = {}
    for (let key in 对象1){
        对象2[key] = 对象1[key]
    }
    
    • Object.assign
    let 对象1 = {
        属性名:属性值
        ...
    }
    let 对象2 = Object.assign({},对象1)
    
    • 扩展运算符
    let 对象1 = {
        属性名:属性值
        ...
    }
    let 对象2 = { ...对象1 }
    
  • 深拷贝
    • JSON.stringify()
    • JSON.parse()
    let 对象1 = {
        属性名:属性值
        属性名:{
            key:value
        }
    }
    let 对象2 = JSON.parse( JSON.stringify(对象1) )
    

ES6

1、解构
// 解构赋值的时候,使用 : 进行重命名

# 解构对象
const {变量1,变量2} = 对象

# 解构数组
const [变量1,变量2] = 数组

# 解构函数参数
function 函数名({变量1, 变量2}) {}
function 函数名([变量1, 变量2]) {}
2、扩展运算符
# 展开字符串
...字符串

# 展开数组
...数组

# 合并数字
[...数组1, ...数组2]

# 浅拷贝数组
const 新数组 = [...要拷贝的数组]

# 浅拷贝对象
const 新对象 = {...要拷贝的对象}

# 合并对象
const 新对象 = {...对象1...对象2}

# rest参数
function 函数名(形参1...rest) {}

# 伪数组变为真数组
const 真数组 = [...伪数组]
3、模板字符串
# 语法
`${表达式}`

# 注意:
1. 表达式:有唯一返回值。
4、对象的简洁写法
const 对象 = {
    name,  // key和value相同,省略
    属性名() {}  // 方法省略 :function
}
5、class
# 类的写法
class 类名 {
    // 相当于在构造函数中写:  this.属性名 = 属性值
    属性名=属性值  
    
    // 构造函数
    constructor() {}
    
    // 原型方法
    方法名() {}
    
    // 静态方法
    static 方法名() {}
}

# 继承
class A {}

class B extends A {
    constructor() {
        super()
        this.属性名=属性值
    }
}
6、模块化语法
# 方式一
export 要导出的东西
import {xx, yy} from '路径或模块名'

# 方式二
export default {}  // 注意: 1个js文件中,只能写1次
import 变量 from '路径或模块名'
7、Promise
  • 基本语法
    new Promise((resolve, reject) => {
    if (成功) {
        resolve('一些成功数据')  // 传递给下一个then
    } else {
        reject('一些失败数据') // 传递给下一个catch
    }
    }).then((data) => {
        // data就是上一步resolve()里面的数据
    }).catch((err) => {
        // err就是上一步 reject()里面的数据
    })
    
  • 解决回调地狱【回调的代码,编成从上往下扁平的代码】
    # 回调地狱
    axios.get(url1).then((res) => {
        axios.get(url2).then((res) => {
        	axios.get(url3).then((res) => {
        	
         	})
         })
    })
    
    # Promise解决代码
    new Promise((resolve) => {
        axios.get(url1).then((res) => { 
            resolve(res.data)
        })
    }).then((data) => {
        return new Promise((resolve) => {
            axios.get(url2).then((res) => { 
                resolve(res.data)
            })
        })
    }).then((data) => {
        return new Promise((resolve) => {
            axios.get(url3).then((res) => { 
                resolve(res.data)
            })
        })
    }).then((data) => {
        console.log(data)
    })
    
8、Async和Await

概念:

  • async:声明函数中有异步代码

  • await:等待Promise结果

    async function 函数名() {
        let 右侧resolve的结果 =   await     Promise的函数调用
    }
    
  • 解决回调地狱

    # 回调地狱
    axios.get(url1).then((res) => {
        axios.get(url2).then((res) => {
        	axios.get(url3).then((res) => {
        	
         	})
         })
    })
    
    # asyncawait解决回调地狱
    async function getData() {
        let 结果1 = await axios.get(url1)
        let 结果2 = await axios.get(url2)
        let 结果3 = await axios.get(url3)
    }
    getData()
    

BOM

1、location(浏览器地址栏)
# 属性  http://www.baidu.com:443/img/logo.png?user=admin&id=666#pid=555

href        // 完整地址  location.href="" 进行跳转 
origin      // 协议 + 域名 + 端口  http://www.baidu.com:443
host        // 域名 + 端口   www.baidu.com:443
hostname    // 域名 www.baidu.com
port       // 端口   443
pathname   // 路径  /img/logo.png
search     // 参数  ?user=admin&id=666
hash       // #pid=555
protocol   // 协议 http

location.href      // 当前地址栏地址
location.search    // 当前地址栏查询字符串
location.reload()  // 刷新页面
2、history(操作历史记录)
history.go()       // 跳转
history.back()     // 向后
history.forward()  // 向前
3、navigator(获取浏览器信息)
navigator.userAgent()  // 获取用户代理信息
navigator.language()   // 获取语言
4、screen(获取屏幕信息)
screen.width()   // 宽度
screen.height()  // 高度
5、window(浏览器窗口对象)
window.alert()  // 弹窗
window.setTimeout() // 定时器
window.onscroll = function () {} // 滚动条滚动
window.onresize = function () {} // 窗口大小发生变化
window.confirm() // 弹出确认框
window.onload = function (){}   // 页面加载完毕
window.open()  // 打开某个网址

// 浏览器窗口尺寸(可视窗口)
window.innerWidth()   // 宽
window.innerHeight()  // 高

DOM

1、操作节点
  • 获取节点
    # H5
    document.querySelector('选择器名')  
    document.querySelectorAll('选择器名')
    
    # H4
    document.getElementById('id名')
    document.getElementsByName('name名')
    document.getElementsByClassName('类名')
    document.getElementsByTagName('标签名')
    
  • 删除节点
    dom.remove()  // 把节点本身删除掉
    dom.removeChild() // 把节点的儿子删除
    dom.innerHTML = ""  // 清空节点
    dom.innerText = ""  // 清空节点内容
    dom.textContent = ""  // 清空节点内容
    
  • 修改节点
    dom.innerHTML = '新的内容'
    dom.innerText = "新的内容"  
    dom.textContent = "新的内容" 
    
  • 添加节点
    const 节点 = document.createElement('节点标签名')
    dom.appendChild(节点)
    
2、操作样式
  • 直接操作style
    dom.style.css属性名 = '新的值'
    
  • 操作类名
    dom.className = "新的类名"
    
3、操作属性
# H4操作属性
    # 标准属性
    dom.属性名  // 获取  dom.id
    dom.属性名 = '新的属性值' // 修改  dom.id = 'box'
    
    # 自定义属性
    dom.getAttribute('属性名')  // 获取自定义属性的值
    dom.setAttribute('属性名', '新的属性值') // 修改自定义属性的值
    dom.removeAttribute('属性名')  // 删除自定义属性的值
# H5操作属性
    # 自定义属性(data-属性名)
    dom.dataset.属性名 // 获取
    dom.dataset.属性名 = '新的值' // 设置
4、DOM事件
  • 绑定事件
    dom.addEventListener(事件类型, function () {
        /* 事件处理函数 */
    })
    
  • 事件类型
    dom.addEventListener(事件类型, function () {
      /* 事件处理函数 */
    })
    
    # 事件类型
    // 鼠标事件
    click        // 点击
    dblclick     // 双击
    contextmenu  // 鼠标右键单击
    mousedown    // 某个鼠标按键被按下
    mouseup     // 某个鼠标按键被松开
    mousemove   // 鼠标被移动
    mouseout    // 鼠标从某元素移开
    mouseover   // 鼠标被移到某元素之上    
    mousewheel  // 滚轮滚动事件
    
    // 键盘事件	
    keydown    // 键盘按下
    keypress   // 某个键盘的键被按下或按住
    keyup     // 某个键盘的键被松开
    
    // 浏览器事件
    load          // 页面加载完毕
    scroll        // 滚动
    resize        // 窗口尺寸改变
    offline       // 网络断开
    online        // 网络恢复
    hashchange    // 哈希值改变了
    
    // 表单事件
    focus      // 聚焦
    change     // 输入框的值发生变化
    submit     // 提交
    input      // 输入
    blur       // 失焦
    reset      // 重置事件,点击 reset 按钮,才能触发
    
    // 触摸事件(移动端)
    touchstart       // 触摸开始
    touchmove        // 触摸移动
    touchend         // 触摸结束
    
  • 事件源
    dom.addEventListener(事件类型, function (e) {
        /* 事件处理函数 */
        e就是事件对象 里面有一些有用的信息
        
        e.target  事件源
        e.preventDefault() // 阻止默认行文
        e.stopPropagation() // 阻止冒泡
    })
    
  • 事件委托(事件委派、事件代理)
    • 概念:给子绑定的事件,绑定在父上面

Ajax

  • 原生ajax
    • get方式
    // 1. 创建ajax对象
    const xhr = new XMLHttpRequest()
    // 2. 配置方式和地址
    xhr.open('get', url?参数名=参数值)
    // 3. 发送请求
    xhr.send()
    // 4. 监听状态变化 接收数据
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            var data = xhr.responseText;
        }
    }
    
    • post方式
    // 1. 创建ajax对象
    const xhr = new XMLHttpRequest()
    // 2. 配置方式和地址
    xhr.open('post', url)
    // 3. 设置请求头
    xhr.setRequestHeader('Content-Type', 'applciation/x-www-form-urlencode')
    // 4. 发送请求
    xhr.send('参数名=参数值')
    // 5. 监听状态变化 接收数据
    xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
            var data = xhr.responseText;
        }
    }
    
  • axios
    • get方式
    # 方式一
    axios.get(url?参数名=参数值).then(res => {
       // res.data就是数据          
    }).catch(err => {
        // err是错误信息
    })
    
    # 方式二
    axios.get(url, {
        parmas: {
            参数名:参数值
        }
    }).then(res => {
       // res.data就是数据          
    }).catch(err => {
        // err是错误信息
    })
    
    • post方式
    axios.get(url, {
        参数名:参数值
    }).then(res => {
       // res.data就是数据          
    }).catch(err => {
        // err是错误信息
    })
    
  • get和post的区别
    • get参数在地址栏,游览器有限制地址栏长度,所以不能传递太多参数,post可以。
    • get参数在地址栏,post参数在请求体
    • get不安全,参数暴露在地址来,post相对安全。
    • get不需要设置请求头(有些时候也需要),post需要设置。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值