20day,21day-函数相关知识,箭头函数,es6相关知识

es6函数相关

自执行函数

  • 一个回自己调用自己的函数
  • 当这个函数定义好后,直接被调用

语法:
=> (function(){代码})()
=》~(function(){代码})()
=》!(function(){代码})()

      // 自调用函数
      (function () {
        console.log("hello world");
      })();

      ~(function(){
        console.log("你好世界");
      })()

      !(function(){
        console.log("你好世界");
      })()

函数默认值

书写:直接在书写函数的时候,以赋值符号 给形参设置默认值就可以了
任何函数都行

      // 以前的做法
      // function add(a,b){
      //   a = a || 10;
      //   b = b || 20;
      //   return a + b;
      // }
      // let res = add(1,2);
      // console.log(res);

      // 允许你在()内设置默认值
      // function add(a = 10,b = 20){
      //   return a + b;
      // }

      // let res = add(100,200);
      // console.log(res); // 300

      // 箭头函数设置默认值时,一定要带上小括号
      let fn = (a=10) =>{
        console.log(a);
      }

      fn()



箭头函数

是 es6 语法中定义函数的一种新方式
只能用来定义函数表达式

当你把函数当作一个值赋值给另一个内容的时候,叫做函数表达式

// 之前的书写方式
// 声明式函数
function f001() {
  // 函数体
}
// 表达式函数
let foo2 = function () {
  // 函数体
};

// 箭头函数完整写法
let foo3 = (name, age) => {
  // 函数体
  console.log(name, age);
};
foo3("zd", 88);

let arr = ["aaa", "bbb", "ccc"];
arr.forEach(function (item, index, arr) {
  console.log(item, index, arr);
});
arr.forEach((item, index, arr) => {
  console.log(item, index, arr);
});

setTimeout(() => {
  console.log("abc");
}, 1000);

注意:声明式函数不可以
语法:()=>{}

  • ()写形参的位置
  • =>是箭头函数的标志
  • {}是书写代码块的位置
箭头函数的特点
  1. 可以省略小括号不写
  • 当形参只有一个的时候,可以不写小括号
  • 如果你的形参没有或者两个及两个以上,必须写
let fn1 = a => {
  console.log(a);
};
fn1(10);

let fn2 = () => {
  console.log("hello");
};
fn2();
let fn3 = (a, b, c, d) => {
  console.log(a, b, c, d);
};
fn3(1, 2, 3, 4);
  1. 可以省略大括号不写
    当你的代码只有一句话的时候,可以省略大括号,并且会自动返回这一句话的结果,否则,必须书写大括号
let fn4 = (a, b) => console.log(a, b);
let res = fn4(10, 20);
console.log(res); // undefined
let fn5 = (a, b) => a + b;
let res2 = fn4(10, 20);
console.log(res); // 30

let fn6 = (a, b) => a + b;

// 清除偶数
let arr2 = [1, 2, 3, 4, 5, 6, 7];
let res3 = arr2.filter(item => item % 2);
console.log(res3);
  1. 箭头函数没有 arguments
let fn1 = function () {
  console.log(arguments);
};
fn1(10, 20, 30, 40, 50);
let fn2 = () => {
  console.log(arguments); // 报错 未定义
};
fn2(10, 20, 30, 40, 50);
箭头函数内 this 的指向

箭头函数中 this 到底指向哪?
不适用那四条规则,而是根据外层作用域来决定
官方:外部作用域的 this
私人:书写在箭头函数外面的那个函数的 this 是谁,箭头函数的 this 就是谁。

console.log(this); // window

let obj = {
  f: function () {
    console.log("f的this", this);
  },
  foo() {
    // foo函数作用域
    // this指向obj
    // 箭头函数继承
    return () => {
      // this指向obj
      console.log("f2的this", this);
    };
  },
  f2: () => {
    console.log("f2的this", this);
  },
};
obj.f(); // obj
obj.f2(); // window
obj.foo()();

// this永远指向函数 运行时 所在的对象(作用域),而不是函数被创建时所在的对象
// js作用域
// 全局作用域
// 局部作用域(函数作用域)

let obj2 = {
  name: "obj2",
  foo() {
    return () => {
      console.log(this); // obj2
      return function () {
        console.log(this); // window
        return () => {
          console.log(this); // window
        };
      };
    };
  },
};

obj2.foo()()()();

/* 
        {
          this obj2
          返回一个fn{
            箭头函数拿上一层作用域this
            this = obj2
            返回一个fn{
              独立调用
              this = window
              返回一个fn{
                箭头函数
                继承上一层的this
                window
                this = window
              }
            }
          }
        }

        
      */

面试题

// 1.
var name = "window";
let person = {
  name: "person",
  sayName: function () {
    console.log(this.name);
  },
};
function sayName() {
  let sss = person.sayName;
  sss(); // 默认绑定 window window
  person.sayName(); // person 隐式绑定 person
  person.sayName(); // person 隐式绑定 person
  (b = person.sayName)(); // window 默认 window
  // 函数间接引用
  // 引用了 person对象中sayName
  // person对象中sayName赋值给了b
  // b()
}
sayName();
// 2.
var name = "window";
let person1 = {
  name: "person1",
  foo1: function () {
    console.log(this.name);
  },
  foo2: () => {
    console.log(this.name);
  },
  foo3: function () {
    return function () {
      console.log(this.name);
    };
  },
  foo4: function () {
    return () => {
      console.log(this.name);
    };
  },
};

let person2 = { name: "person2" };

//题目开始
person1.foo1(); // 隐式绑定 person1
person1.foo1.call(person2); // 显示绑定 person2
person1.foo2(); // 默认 外层作用域 window
person1.foo2.call(person2); // 外层 window 箭头函数 没有this call无效
person1.foo3()(); // 默认绑定 window
person1.foo3.call(person2)(); // person2 显示绑定
// window
// 改this为person2 改的是 f003
// foo3 return 出来的函数 没改
// 默认绑定 window
person1.foo3().call(person2); // 显示绑定 person2
// 这里改的就是foo3函数return出来的函数指向
// 指向了person2
person1.foo4()(); // 默认绑定 window 默认绑定 person1
// 把foo4指向person1
// return ()=>{} 拿到foo4的this
// person1 person1
person1.foo4.call(person2)(); // person2

person1.foo4().call(person2); // person1
// foo4内的this -》person1
// 箭头函数call没用 找外层 person1

// 3.
var name = "window";
function Person(name) {
  this.name = name;
  this.foo1 = function () {
    console.log(this.name);
  };
  this.foo2 = () => console.log(this.name);
  this.foo3 = function () {
    return function () {
      console.log(this.name);
    };
  };
  this.foo4 = function () {
    return () => {
      console.log(this.name);
    };
  };
}

let person1 = new Person("person1");
let person2 = new Person("person2");
person1.foo1(); // 隐式绑定 person1
person1.foo1.call(person2); // 显示绑定 person2
person1.foo2(); // person1 上层作用域
person1.foo2.call(person2); // person1 上层作用域
person1.foo3()(); //默认绑定 window
person1.foo3.call(person2)(); // 默认绑定 window
person1.foo3().call(person2); // person2
person1.foo4()(); // person1
person1.foo4.call(person2)(); // person2
person1.foo4().call(person2); // person1

// 4.
var name = "window";
function Person(name) {
  this.name = name;
  this.obj = {
    name: "obj",
    foo1: function () {
      return function () {
        console.log(this.name);
      };
    },
    foo2: function () {
      return () => {
        console.log(this.name);
      };
    },
  };
}

let person1 = new Person("person1");
let person2 = new Person("person2");
person1.obj.foo1()(); // window
person1.obj.foo1.call(person2)(); // window
person1.obj.foo1().call(person2); // person2
person1.obj.foo2()(); // person1 obj
person1.obj.foo2.call(person2)(); // person2
person1.obj.foo2().call(person2); // obj


es6 相关

定义变量

es6 新增了两个定义变量的关键字

  1. let 变量
  2. const 常量
var/let/const 的区别
  1. 变量提升
  • var:会进行预解析,可以先使用后定义。
  • let/const 不会进行预解析,必须先定义后使用。
console.log(a);
var a = 10;
console.log(a);
// console.log(b); // 报错
let b = 20;
console.log(b);
console.log(c); // 报错
const c = 30;
  1. 变量重名
    var 定义的变量可以重名,只是第二个没有意义
    let/ const 不允许同一作用域下定义重名变量
// var a = 10;
// var a = 20;
// console.log(a); // 20

// let/ const 不允许同一作用域下重名
let a = 10; // 报错
//  let a = 20;
//  const a = 30; // 报错
function foo() {
  let a = 20;
}
function fn() {
  const a = 30;
}
  1. 块级作用域
  • var 没有
  • let/const 有
  • 块级作用域:任何一个可以书写代码的{}都会限制变量的使用范围
let n = 100;
if (1) {
  // let n = 200;
  n = 200;
  console.log(n); // 200
}
for (let i = 0; i < 5; i++) {
  let n = 300;
  console.log(n); // 300
}
console.log(n); // 200
let/const 区别
  1. 声明时的赋值
  • let 可以不赋值
  • const 必须赋值,否则报错
let a;
console.log(a); // undefined
a = 200;
console.log(a); // 200
// const b;// 报错 没有初始化
  1. 值的修改
  • let 定义的变量可以修改值的内容
  • const 不行
let n = 100;
n = 200;
console.log(n);
const m = 10;
// m = 20;
// console.log(m); // 报错 你尝试把一个变量赋值给常量

// obj是复杂数据类型 / 存的是地址
// 当你修改复杂数据类型的值时,obj地址未改变
const obj = {
  a: 1,
};
obj.a = 20;
obj.b = 30;
console.log(obj.a);
console.log(obj.b);
// 这样才是在改变obj的值
obj = [];
模版字符串

(``)里面可以识别变量
通过${}在其中就可以识别变量

语法:正常写入字符串${变量名}正常写入字符串

块级作用域

在 ES6 之前,JS 中存在两种作用域

  • 全局作用域(全局执行上下文)
  • 函数作用域(函数执行上下文)

在 ES6 引入了 let const 从而拥有了块级作用域

为什么要引入块级作用域?(或者说没有块级作用域有什么影响?)
会导致函数中的变量无论在哪里声明的,在编译阶段都会被提取到执行上下文的变量环境中,所以这些变量在整个函数体内部的任何地方都能被访问。这也就是 js 中的变量提升

变量提升带来的问题
  1. 变量容易在不被察觉的情况下被覆盖
var a = "zd";
function fn() {
  console.log(a);
  if (0) {
    var a = "qt";
  }
  console.log(a);
}
fn();
// undefined

/* 
      接着执行第一行代码
      console.log(a);
      执行这段代码需要使用到变量a,结合刚才的调用栈状态图,可以看到这里有两个a变量,一个在全局执行上下文中,值为yh,另一个在fn函数的执行上下文中值为undefined,
      根据作用域的访问机制
      访问当前作用域中的变量a
      得到undefined
    */
  1. 本应销毁的变量没有被销毁
function foo() {
  for (var i = 0; i < 7; i++) {}
  console.log(i);
}
foo();
// 同样是由于变量提升导致,在创建执行上下文阶段,变量i就已经被提升了,所以当for循环结束后,变量i并没有被销毁
js 怎么支持的块级作用域的
  1. 一步编译并创建执行上下文
  • 通过上图已知
  • 函数内部通过 var 声明的变量,在编译阶段全都被保存放到变量环境里面了
  • 通过 let 声明的变量,在编译阶段会被存放到词法环境中
  • 在函数内部的块作用域,通过 let 声明的变量并没有被存放到词法环境中
  1. 执行代码
  • 变量环境中的 a 的值被赋值为 1,词法环境中 b 的值被赋值为 2.

  • 当进入函数的块作用域中时,会在词法环境中生成一个新的区域,这个区域中的变量并不影响块作用域外面的变量。

    作用域外面声明的变量 b,在该作用域内部也声明了变量 b,当执行到作用域内部时,他们都是独立的存在

在词法环境中,相当于维护了一个小型的栈结构,栈底是函数最外层的变量,进入一个块作用域后,就会把该作用域内部的变量压到栈顶;当作用域执行完成后,该作用域信息就会从栈顶弹出。这就是词法环境的结构。

  1. 当执行到 console.log(a) console.log(b)时
    需要在词法环境中和变量环境中查找变量 a 的值。
    查找方法:
    沿着词法环境的栈顶向下查询,如果在词法环境中的某个块中查找到了,就直接返回给 js 引擎,如果没有查到,那么就继续在变量环境中查找。

  2. 当块作用域执行结束之后,其内部定义的变量就会从词法环境的栈顶弹出。

解构赋值

快速从对象/数组中获取你要的数据

数组
  • 使用[]解构数组
  • 语法:var/let/const [变量 1,变量 2,…] = 数组
  • 按照索引,依次从数组中每一个变量赋值
const arr = ["金拱门", "德克士", "华莱士", "kfc", "翰博king"];
// 原来的做法
// let a = arr[0];
// console.log(a);
// let 变量 = 数组[索引下标]
// es6语法
const [a, b, c, d, e] = arr;
console.log(a, b, c, d, e); // 金拱门 德克士 华莱士 kfc 翰博king
console.log(a); // 金拱门
const [f, g] = arr;
console.log(f, g); // 金拱门 德克士

// 多维数组
const arr = [1, 2, 3, [4, 5, [6, [7, 8, 9]]]];
// let a = arr[3][2][1][2];
// console.log(a);
// const [a,b,c,[d,e,[f,[g,h,i]]]] = arr;
// console.log(i);

// let a = 10;
// let b = 20;
// [a,b] = [b,a]
// console.log(a);
// console.log(b);

// 使用逗号跳过索引
const [, , , [, , [, [, , a]]]] = arr;
console.log(a);
对象
  • 语法:var/let/const {键名 1,键名 2} = 对象
  • 注意:{}解构对象
解构时起别名
  • 语法:var/let/const {键名 1:别名,键名 2:别名} = 对象
  • 注意:当你起了别名之后,原先的键名就不能再当作变量名了;来使用了,需要用这个别名
const obj = { name: "zd", age: 88, gender: "男" };
// let age = 18;
// 以前
// let name = "name";
// console.log(window);
// let userName = obj["name"];// obj["name"]
// console.log(userName);
// const {name,age,gender} = obj;
// console.log(name,age,gender);// zd 88 男

// 解构的时候起个别名
const { name: a, age: b, gender: c } = obj;
// let a = obj.name
// let b = obj.age
// let c = obj.gender
console.log(a, b, c);
console.log(name); // 打印的是window下的name属性
// 当你起了别名之后,原先的键名就不能再当作变量名了;来使用了,需要用这个别名
console.log(age); //报错

扩展运算符...

es6 的扩展运算符,又叫做展开合并运算符
有两个意义:展开,合并
主要是操作 数组和对象的运算符号

私人:打散,聚拢

打散

打散对象/数组
如果是打散数组,就是去掉数组的[]
如果是打散对象,就是去掉对象的{}

  1. 数组
const arr = [1, 2, 3, 4];
console.log(arr[0], arr[1], arr[2], arr[3]);
console.log(...arr);

const arr2 = [...arr, 5, 6, 7];
// [1,2,3,4,5,6,7]
console.log(arr2);

const res = Math.max(...arr2);
console.log(res);

let lis = [...document.querySelectorAll("li")];
let res1 = lis.filter(item => item.innerText % 2);
console.log(res1);
  1. 对象
      const o1 = {name:"老夹子",age:88};
      // 允许的
      const o2 = {
        gender:"男",
        ...o1,
      }
      console.log(o2);

      // console.log(...o1); // 报错
      function fn(){}
      // fn(...o1) // 报错
      // 允许的
      console.log({...o1});
聚拢

当这个符号书写在函数的形参位置的时候,叫合并运算符
从当前形参的位置开始获取实参,一直到末尾
注意:合并运算符一定要写在最后一位形参位置上

      const fn = function(a,b,...c){
        console.log(arguments);
        console.log(a,b,c);
      }
      fn(1,2,3,4,5,6,7,8,9)

      // 给箭头函数一个实参数组
      const fn2 = (...arg)=>{
        console.log(arg);
        console.log(arg.filter(item=>item > 3));
      }
      fn2(1,2,3,4,5,6,7,8)

for…of循环

是ES6新引入的一种遍历所有数据结构的统一方式。

所有数据结构:部署了[Symbol.iterator]属性的数据结构

使用

      // 遍历数组
      let arr = [1, 2, 3, 4, 5];
      for (let item of arr) {
        console.log(item); // 数组的值
        // 如果想要在forof中拿到数组的索引
        // indexOf
        // 设置一个变量从0开始记录

        // 可以通过 entries 可以获取到数组中每一项的键名与键值 每一项以一个数组形式返回,这个数组的0项是当前的索引(键名),1项是键值
        // 键名:数组的下标索引
        // 键值:数组当前想的值
        // console.log(Object.entries(arr));
        // keys 返回是一个数组,数组里面装载的是当前对象的键名
        console.log(Object.keys(arr));
        // values 返回是一个数组,数组里面装载的是当前对象的键值
        console.log(Object.values(arr));
      }

      // 遍历对象
      let obj = {
        name: "zd",
        age: 8,
      };
      // for(let k of obj){
      //   console.log(k); // 报错,obj不可迭代
      // }
      let objKeys = Object.keys(obj);
      console.log(objKeys);
      for(let key of objKeys){
        console.log(obj[key]);
      }

      let objValues = Object.values(obj);
      console.log(objValues);
      function foo(a,b) {
        console.log(a);
        console.log(b);
      }
      foo(...objValues)
for of与for in的区别
  • for in只是获取数组的索引,for of会获取数组的值
  • for in会遍历对象的整个原型链,性能差;而for of 只遍历当前对象,不会遍历原型链
  • 对于数组的遍历,for in会返回数组中所有可枚举属性(包含原型链上的可枚举属性);for of
  • for in循环主要是为了遍历对象而设计的,不适用于遍历数组
  • for of使用遍历数组/字符串/map/set 等有迭代器对象的集合但是不能遍历普通对象

新增数据类型

Symbol

  • ES6引入了一种新的基本数据类型 Symbol,表示独一无二的值。
  • Symbol 值 通过Symbol()函数生成。

这就是说,对象的属性名现在可以有两种类型,一种是原来的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol 类型,就都是独一无二的,可以保证不会与其他的属性名产生冲突。

    let s = Symbol();
    console.log(s);
    let s2 = Symbol();
    console.log(s == s2);

    console.log(typeof s); // symbol

    // 注意:Symbol函数前面不能使用 new 命令,否则会报错
    let s3 = new Symbol(); // Uncaught TypeError: Symbol is not a constructor

这是因为生成的Symbol是一个基本数据类型,不是对象,所以不能用new名来调用。另外,由于Symbol值不是对象,所以也不能添加属性。基本上他是一种类似于字符串的数据类型。

  • Symbol()函数可以接受一个字符串作为参数,表示对Symbol实例的描述。主要是为了在控制台显示,或者转为字符串时,比较容易区分。
    let s4 = Symbol("zd");
    console.log(s4);
    let s5 = Symbol("qt");
    console.log(s4 === s5);
    let s6 = Symbol("zd");
    console.log(s4 === s6);

    // Symbol函数的参数只是表示对当前Symbol值的描述,因此相同参数的Symbol函数返回的值是不想等的。

    console.log(s5.toString());
    console.log(s6.toString());
  • 注意:Symbol值可以转成字符串和布尔值,但是不能转为数值
    console.log(s5.toString());
    console.log(s6.toString());

    let s7 = Symbol("jh");
    console.log(Boolean(s7));
    console.log(!s7);

    console.log(Number(s7)); // 报错
读区Symbol的描述 Symbol.description

正常情况下,我们想要读区Symbol的描述需要讲Symbol转为字符串

    let s1 = Symbol("rb");
    console.log(String(s1));// Symbol(rb)
    console.log(s1.toString());// Symbol(rb)

    // 在 ES2019中提供了一个Symbol值的实例属性 description,可以直接返回 Symbol的描述
    
    console.log(s1.description); // rb
作为属性名的Symbol
  • 由于Symbol唯一的特性,将Symbol用于对象的属性名,就能保证不会出现同名属性 。
    let mySymbol = Symbol();

    // 第一种写法
    let obj = {};
    obj[mySymbol] = "Hello";

    console.log(obj);
    console.log(obj[mySymbol]);

    // 第二种写法
    let obj2 = {
      [mySymbol]:"Hello",
    }

    console.log(obj2);
    console.log(obj2[mySymbol]);

    // 第三种写法
    let obj3 = {
      [Symbol("name")]:"yh",
      [Symbol("age")]:18,
      gender:"man"
    }

    // 注意:Symbol值作为对象属性名时,不能使用点运算符

    let obj4 = {};
    obj4.mySymbol = "Hello";
    // 因为点运算符后面总是字符串,所以不会读取mySymbol作为标识名所指代的那个值
    // 导致obj4的属性名实际上是一个字符串,而不是一个Symbol值
    console.log(obj4[mySymbol]);
    console.log(obj4["mySymbol"]);

    // 同理,在对象内部,使用Symbol值定义属性时,Symbol值必须放在方括号中。
    let obj5 = {
      mySymbol:"Hello",
    }
    console.log(obj5);

其他应用

  // 其他应用
  // 将Symbol作为值的一大好处在于,在做某些条件判断的时候,不会因为出现相同的值而导致程序出错,保证程序按照我们的设计的方式工作。
  const color_red = Symbol("red");
  const color_green = Symbol("green");

  function Color(color){
    switch (color){
      case color_red:
        console.log("red");
      break;
      case color_green:
        console.log("green");
      break;
    }
  }
  let res = color_green;
  Color(res)
遍历带有Symbol作为键名的对象
  • Symbol作为键名时,该属性不会出现在for in循环中。
获取指定对象中所有的Symbol属性名
  • 语法:Object.getOwnPropertySymbols(你要获取的对象)
  • 返回值:返回一个数组,里面装载的就是当前这个对象中所有作为属性名的Symbol值
  let obj = {
    [Symbol("name")]:"zd",
    [Symbol("age")]:28,
    [Symbol("gender")]:"男",
    height:150
  }
  console.log(obj);
  let objSymbols = Object.getOwnPropertySymbols(obj);
  console.log(objSymbols);
  console.log(obj[objSymbols[0]]);
  • 语法:Reflect.ownKeys(要获取的对象)
  • 返回值:返回一个数组,里面装载的是这个对象中所有数据的键名(所有类型的键名,包含常规键名和Symbol键名)
  let objKey = Reflect.ownKeys(obj);
  console.log(objKey); //  ['height', Symbol(name), Symbol(age), Symbol(gender)]
Symbol.for()

有时我们想要重新使用同一个Symbol值,但Symbol的特性让每一次生成一个全新的Symbol值。

  • 作用:用于创建多个相同的Symbol值
  • 语法:Symbol.for(“名称”)
  let a = Symbol("foo");
  let b = Symbol.for("foo")
  let c = Symbol.for("foo")

  console.log(a === b); // false
  console.log(b === c); // true

原理:通过for创建的Symbol值,他接受一个字符串作为参数,之后会被登记在全局环境中供搜索,每次通过for创建Symbol值时,他首先会在全局环境中根据你提供的名称(key)搜索,如果检查出给定的key不存在才会创建一个新的值,否则将返回检查到的 Symbol 值。

  let a = Symbol("foo");
  let b = Symbol.for("foo")
  let c = Symbol.for("foo")
  // let c = b;

  console.log(a === b); // false
  console.log(b === c); // true

  let e = Symbol.for()
  let f = Symbol.for()
  let g = Symbol.for("")
  console.log(e===f); // true
  console.log(f===g); // false
  let i = Symbol.for();
  console.log(i === e);// true
  let j = Symbol.for("")
  console.log(j === g); // true
  let k = Symbol.for(null);
  console.log(k === e);// false
Symbol.keyFor();
  • 返回一个已登记的Symbol类型值的key(名称
    )
  • 语法:Symbol.keyFor(Symbol值)
  // 变量s1属于未登记,所以返回undefined
  let s1 = Symbol("foo");
  console.log(Symbol.keyFor(s1)); // undefined

  let s2 = Symbol.for("foo");
  console.log(Symbol.keyFor(s2)); // foo
  • 13
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值