ES6有何新特性?(下篇)

目录

函数参数的默认值设置

rest参数

扩展运算符

Symbol

迭代器

生成器

Promise

Class

数值扩展

对象方法扩展

模块化


大家好呀!今天这篇文章继续为大家介绍ES6的新特性,上上上篇文章介绍了一部分,这篇文章会将剩下的部分新增的特性都介绍到。希望对你有帮助!

函数参数的默认值设置

ES6允许给函数参数赋值初始值,可以给形参赋初始的值,并且可以给参数指定默认的值,若给参数没有传入相应的值,则会使用默认的值。

  function add(a,b,c){return a+b+c;}let result=add(1,2);console.log(result)//NaN

以上的这种情况,传入的数值与形参的数量不一样,则最后的一个形参则会传入underfine,因此1+2+underfine则会输出NaN。同时我们可以为第三个形参赋默认的值,具有默认值的参数一般都需要放在最后一个。具体代码如下:

 // 形参初始值function add(a,b,c=10){return a+b+c;}
let result=add(1,2);
console.log(result)//13

除此之外,它还可以与解构赋值进行结合。可以使得获取传入的值更加方便。比如我们为一个函数传入一个对象,在函数的内部输出对象中的属性,我们传统的方式可以如下:

function connect(option){console.log(option.name)console.log(option.age)console.log(option.sex)}connect({name:'N-A',age:5,sex:"男"})

以上的方式会让我们觉得比较地麻烦,需要反复地使用option来进行调用,若使用函数参数结合对象解构赋值的方式来实现,则会更加地方便,具体实现如下:(同时也可以与上述的功能一样,为参数赋初始的值)

 function connect({name,age,sex}){console.log(name)console.log(age)console.log(sex)}connect({name:'N-A',age:5,sex:"男"})

rest参数

rest参数主要是用来获取函数的实参。它可以用来替换arguments,与arguments的作用相似。在ES5中使用arguments来获取函数的实参的方法如下:

 function date(){console.log(arguments)}date("N-A","5","男")

输出的结果是一个对象,而使用ES6新增的rest参数输出的结果是一个数组,因此数组更加方便我们对其进行一定的操作。具体的写法如下:

      // rest参数function date(...args){console.log(args)}date("N-A","5","男")// 若有多个参数,则rest参数必须要放到参数的最后function fn(a,b,...args){console.log(a);//1console.log(b);//2console.log(args);//[3,4,5,6,7,8]}fn(1,2,3,4,5,6,7,8)

注意:若有多个参数,则rest参数必须放到参数的最后。

扩展运算符

扩展运算符能将数组转为逗号分隔的参数序列。他的使用方式也是使用...与rest参数优点相似,但是他们一个是在函数声明时的参数使用,一个是在函数调用时使用。具体用法如下:

        const data=[1,2,3,4]function result(){console.log(arguments);}result(...data);//相当于result(1,2,3,4)

扩展运算符还有以下的一些用途,数组的合并,在ES5中我们使用concat可以实现数组的合并,在ES6中使用拓展运算符同样可以实现数组的合并,且更加的方便。

 const data1=[1,2,3,4]const data2=[5,6,7,8]//    传统的方式const result=data1.concat(data2)//[1,2,3,4,5,6,7,8]// 扩展运算符const result2=[...data1,...data2]//[1,2,3,4,5,6,7,8]

除此之外,扩展运算符还可以实现数组的克隆,但是使用它进行克隆是浅拷贝的克隆。也可以让伪数组变成真正的数组。

    // 数组的克隆const data1=[1,2,3,4]const data2=[...data1]console.log(data2)//[1,2,3,4]// 将伪数组变成真数组// html部分代码省略const divs=document.querySelectorAll("div")const divArr=[...divs];console.log(divArr)

Symbol

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据型。

1) Symbol 的值是唯一的,用来解决命名冲突的问题

2) Symbol 值不能与其他数据进行运算

3) Symbol 定义 的 对象属 性 不能 使 用 for…in 循 环遍 历 ,但 是可 以 使 用Reflect.ownKeys 来获取对象的所有键名

        // 创建Symbollet s=Symbol();let s2=Symbol("N-A");let s3=Symbol("N-A");console.log(s2==s3);//false// 使用Symbol.for创=创建let s4=Symbol.for('N-A');let s5=Symbol.for('N-A');console.log(s4==s5);//true

它可以为对象添加属性和方法,让该属性或者方法是独一无二的,就算原本的对象中有一个同名的方法,它也能够进行添加成功。同时也能够保持其安全性,不会破坏对象原本的属性和方法。

 let plan={name:"N-A",study(){console.log("今天学习ES6");},sport(){console.log("今天去游泳");}};// 声明一个对象let methods={study:Symbol(),sport:Symbol()};plan[methods.study]=function(){console.log("今天学习Vue.js")};plan[methods.sport]=function(){console.log("今天去跑步")};console.log(plan);// 方法二let plan={name:"N-A",[Symbol('study')]:function(){console.log("今天学习ES6");},[Symbol('sport')]:function(){console.log("今天去游泳");}};

除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。

以第二个例子,其使用方式如下:

const arr=[1,2,3,4];const arr2=[5,6,7,8];//   不可展开arr2[Symbol.isConcatSpreadable]=false;console.log(arr.concat(arr2))//[1, 2, 3, 4, Array(4)]

迭代器

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

ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费。原生具备 iterator 接口的数据(可用 for of 遍历)有:Array、Arguments、Set、Map、String、TypedArray、NodeList。

其工作原理如下:首先创建一个指针对象,指向当前数据结构的起始位置。第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员。接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员。每调用 next 方法返回一个包含 value 和 done 属性的对象。

 const study=['ES6','Vue','Webpack','CSS'];// 使用for...of遍历数组for(let item of study){console.log(item)}// 原理let iterator=study[Symbol.iterator]();// 调用对象的next方法console.log(iterator.next());//{value: 'ES6', done: false}console.log(iterator.next());//{value: 'Vue', done: false}console.log(iterator.next());//{value: 'Webpack', done: false}console.log(iterator.next());//{value: 'CSS', done: false}console.log(iterator.next());//{value: undefined, done: true}

它可以用于自定义遍历数据,以一个实例来进行演示,假如有一个对象,对象中有一个两个属性,一个为name,一个为study。study为一个数组,现在需要使用for...of来进行遍历(不考虑其他方式),该如何实现。

  const plan={name:'N-A',study:['ES6','Webpack','Vue','CSS'],[Symbol.iterator](){// 声明索引变量let index=0;return{next:()=>{if(index<this.study.length){const result={value:this.study[index],done:false};index++;return result;}else{return {value:undefined,done:true}}}}}}for(let item of plan){console.log(item)}

生成器

生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

  function* gen() {yield '一只没有耳朵';yield '一只没有尾巴';yield '真奇怪';}let iterator = gen();console.log(iterator.next());//{value: '一只没有耳朵', done: false}console.log(iterator.next());//{value: '一只没有尾巴', done: false}console.log(iterator.next());//{value: '真奇怪', done: false}console.log(iterator.next());//{value: undefined, done: true}

以上的代码* 的位置没有限制,可以偏左偏右或者处于中间。生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到yield 语句后的值。yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next方法,执行一段代码。next 方法可以传递实参,作为 yield 语句的返回值。

 function * gen(arg){console.log(arg);//AAAAlet one=yield 111;console.log(one);//BBBlet two=yield 222;console.log(two);;//CCClet three=yield 333;console.log(three);//DDD}let iterator=gen('AAAA');console.log(iterator.next());// next方法传入实参console.log(iterator.next('BBB'));console.log(iterator.next('CCC'));console.log(iterator.next('DDD'));

同时还可以在next()中传入实参,传入的数据会作为上一次yield语句的返回结果。

应用实例如下:现在我们需要实现1s之后在控制台打印111,然后再过2s之后在控制台打印222,在过3s之后在打印333。可以使用传统的函数回调进行实现,但是代码的可读性以及维护性并不好,同时也会存在回调地狱的问题,因此使用生成器来实现具体如下:

 function one(){setTimeout(()=>{console.log(111);iterator.next();},1000)}function two(){setTimeout(()=>{console.log(222);iterator.next();},2000)}function three(){setTimeout(()=>{console.log(333);iterator.next();},3000)}function * gen(){yield one();yield two();yield three();}//   调用生成器函数let iterator=gen();iterator.next();

Promise

Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

  // 实例化Promise对象const p=new Promise(function(resolve,reject){setTimeout(function(){let data='数据库中的数据';// 调用resolve,让其结果为成功,让p实例的状态为成功,会执行then方法中成功的回调。// resolve(data);// 让其状态为失败let err='请求失败';reject(err);})});// 调用promise对象的then()方法p.then(function(value){console.log(value);},function(reason){console.error(reason);})

首先需要实例化Promise对象,Promise()接受有个参数,该参数为一个函数,函数有两个参数:resolve以及reject。在后续调用resolve时,promise对象的状态就会变成成功,reject则会失败。当对象的状态发生改变时,就会调用then方法,该方法有两个函数,成功的回调函数以及失败的回调函数。若promise对象的状态为成功则执行成功的对调,否则执行失败的回调。

使用promise封装ajax请求具体实现如下:

        const p = new Promise((resolve, reject)=>{const xhr = new XMLHttpRequest();xhr.open("GET", "https://api.apiopen.top/getJoke");xhr.send();xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {resolve(xhr.response);} else {reject(xhr.status);}}}})p.then(function(value){console.log(value);},function(reason){console.error(reason);})

Promise中的then方法,返回的结果是一个Promise对象,对象的状态由回调函数的执行结果决定。如果回调函数中返回的结果是非promise类型的属性,状态为成功,返回的值为对象的成功的值。若没有return返回结果,则同样是成功的状态,只是对应的值为undefined。

 const p = new Promise((resolve, reject) => {setTimeout(() => {resolve("用户数据");}, 1000)});const result = p.then(value => {console.log(value);return 1234;}, reason => {console.error(reason);});console.log(result);//[[PromiseState]]: "fulfilled" (代表成功)  [[PromiseResult]]:1234

若返回的是一个promise对象,then返回的状态则为return中promise对象的状态,其值也是对应的内部return中promise的值。

 const p = new Promise((resolve, reject) => {setTimeout(() => {resolve("用户数据");}, 1000)});const result = p.then(value => {console.log(value);return new Promise((resolve,reject)=>{resolve('ok');});}, reason => {console.error(reason);});console.log(result);//[[PromiseState]]: "fulfilled" (代表成功)  [[PromiseResult]]:ok

若是抛出错误,则then返回的promise对象的状态为失败的状态,对应的值为抛出的值。

 const p = new Promise((resolve, reject) => {setTimeout(() => {resolve("用户数据");}, 1000)});const result = p.then(value => {console.log(value);throw new Error('出错啦!')}, reason => {console.error(reason);});console.log(result);//[[PromiseState]]: "rejected"  [[PromiseResult]]:Error: 出错啦!

promise中的catch方法,相当于是then方法中的第二个回调函数,promise实例的状态失败时执行的方法。

        const p = new Promise((resolve, reject) => {setTimeout(() => {reject("出错啦!");}, 1000)});p.catch(function(reason){console.log(reason);})

Class

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

        class Phone{constructor(band,price){this.band=band;this.price=price;}call(){console.log("我可以电话!!")}}let type=new Phone("Huawei",5999);

class中的静态成员,使用static声明的属性以及方法属于类,并不属于实例对象。因此使用实例对象无法访问。具体代码如下:

      class Phone{// 声明静态属性static name='手机';static change(){console.log("我可以改变世界");}}let type=new Phone();console.log(type.name);//undefinedconsole.log(Phone.name)//手机

同时还可以使用calss来实现继承,具体代码如下。子类可以对父类的方法进行重写,但是无法使用super来调用父类同名的方法。

      class Phone{constructor(brand,price){this.brand=brand;this.price=price;}call(){console.log("我可以打电话");}}class SmartPhone extends Phone{constructor(brand,price,color){super(brand,price);//相当于Phone.call(this,brand,price)this.color=color;}phone(){console.log("拍照")}}const type=new SmartPhone('小米',2987,'白色');

数值扩展

1.Number.EPSILON是js表示的最小进度。若两个数的差值小于它,就认为这两个数相等。

2.ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。

3.Number.isFinite() 用来检查一个数值是否为有限的。Number.isNaN() 用来检查一个值是否为 NaN。

4.Number.parseInt() 与 Number.parseFloat() 。用于将字符串转为整数或者浮点数,若字符串中包含不能转化的字符,则不会在往后转换。

5.Math.trunc,用于去除一个数的小数部分,返回整数部分。

6.Number.isInteger() 用来判断一个数值是否为整数。

7.Math.sign,用于检测一个数为正数,负数或者为零。若为正数则会返回1,若为零则会返回0 ,若会负数则会返回-1。

对象方法扩展

1) Object.is 比较两个值是否严格相等,与===行为基本一致,主要区别在于Object.is判断两个NaN是返回的是true,而使用===返回的是false。

2) Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象。后面的对象会覆盖前面对象中具有同名的属性。若不同名则会合并。

3) Object.setPrototypeOf、 Object.getPrototypeOf 可以直接设置对象的原型,以及获取对象的原型。

模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。它可以防止命名冲, 代码复用以及使得代码的维护性更高。

ES6 之前的模块化规范有:1) CommonJS => NodeJS、Browserify 2) AMD => requireJS 3) CMD => seaJS

模块功能主要由两个命令构成:export 和 import。export 命令用于规定模块的对外接口。 import 命令用于输入其他模块提供的功能。暴露的方式如下

方法一:分别暴露,编写一个index.js文件,代码如下:

//分别暴露
export let name='N-A';
export function study(){
console.log("学习ES6新特性")
}

在主文件中使用通用的引入方式。

<script type="module">//引入index.js模块的内容,全部引入import * as m1 from "./src/js/index.js";
</script>

方法二:统一暴露,编写一个index.js文件,在主文件中进行引入,引入方法同上。代码如下:

//统一暴露
let name='N-A';
function study(){
console.log("学习ES6新特性")
}
export {name,study};

方式三:默认暴露,编写一个index.js文件,引入方法同上。代码如下:

//默认暴露
export default{
let name='N-A';
function study(){
console.log("学习ES6新特性")
}
}

如果使用该方法进行编写的话,在主文件中想要获取到相应的方法或者属性需要再增加一层default进行调用。

导入文件的方式除了上面提到的通用方法之外,还可以使用如下的方法。

//解构赋值形式
import {name,study} from "./src/js/index.js";
//若名字重复现需要其别名
import {name as ming,sport} from "./src/js/index2.js";
import {default as def} from "./src/js/index.js";
//简便形式,只能用于默认暴露的方式
import m from './src/js/index.js'

若引入的文件较多,都写在script标签中会使代码编写不简洁,因此可以单独地创建一个js文件来编写文件的import引入,然后再在主文件中的script标签通过src属性进行引入,然后script标签还需要增加一个type等于“module”的属性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/199357.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【CHI】Ordering保序

本节介绍CHI协议所包含的支持系统保序需求的机制&#xff0c;包括&#xff1a; • Multi-copy atomicity • Completion response and ordering • Completion acknowledgment • Transaction ordering 一、 Multi-copy atomicity CHI协议中所使用的memory model要求为mu…

怎么在echarts图上左右滑动切换数据区间

说在前面 不管前端还是后端&#xff0c;大家或多或少都了解使用过echarts图表吧&#xff0c;很多时候我们只是需要展示指定区间的数据&#xff0c;但有时我们希望在图表上能够轻松地切换数据的展示区间&#xff0c;以便更清晰地观察特定时间段或区域的变化。在本文中&#xff0…

电子学会C/C++编程等级考试2022年06月(一级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:倒序输出 依次输入4个整数a、b、c、d,将他们倒序输出,即依次输出d、c、b、a这4个数。 时间限制:1000 内存限制:65536输入 一行4个整数a、b、c、d,以空格分隔。 0 < a,b,c,d < 108输出 一行4个整数d、c、b、a,整数之…

听GPT 讲Rust源代码--src/bootstrap

图片来自 使用rust的image库进行图片压缩[1] File: rust/src/bootstrap/build.rs 在Rust源代码中&#xff0c;rust/src/bootstrap/build.rs这个文件是一个构建脚本。构建脚本是一个在编译Rust编译器本身时运行的程序&#xff0c;它用于初始化和配置Rust编译器的构建过程。build…

沸点 | Ultipa 图数据库金融应用场景优秀案例首批入选,金融街论坛年会发布

为推进图数据库在金融行业的创新应用试点&#xff0c;近日&#xff0c;在2023金融街论坛年会“全球金融科技中心网络年会暨ZIBS北京论坛”上&#xff0c;北京前沿金融监管科技研究院发布了基于国际标准组织——国际关联数据基准委员会&#xff08;LDBC&#xff09;的《图数据库…

c语言:矩阵交换

题目&#xff1a; 代码和思路&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<stdio.h>int main() {int n 0;int m 0;int arr[10][10] { 0 }; // 输入行和列scanf("%d%d", &n, &m);int i 0;int j 0;//读取数组for (i 0; i < n; i)…

python爬虫SHA案例:某直播大数据分析平台

声明&#xff1a; 该文章为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;违者后果自负&#xff0c;由此产生的一切后果均与作者无关 一、找出需要加密的参数 js运行 atob(‘aHR0cDovL3d3dy5oaDEwMjQuY29tLyMvc2VhcmNoL3NlYXJjaA’) 拿到网址&#xff0c;F12打…

Linux本地WBO创作白板部署与远程访问

文章目录 前言1. 部署WBO白板2. 本地访问WBO白板3. Linux 安装cpolar4. 配置WBO公网访问地址5. 公网远程访问WBO白板6. 固定WBO白板公网地址 前言 WBO在线协作白板是一个自由和开源的在线协作白板&#xff0c;允许多个用户同时在一个虚拟的大型白板上画图。该白板对所有线上用…

将word中的表格无变形的弄进excel中

在上篇文章中记录了将excel表拷贝到word中来&#xff1a; 记录将excel表无变形的弄进word里面来-CSDN博客 本篇记录&#xff1a;将word中的表格无变形的弄进excel中。 1.按F12&#xff0c;“另存为...”&#xff0c;保存类型&#xff1a;“单个文件页面”&#xff0c;保存。…

CXL崛起:2024启航,2025年开启新时代

在2019年&#xff0c;Intel主导联合多家阿里巴巴、Facebook(也就是改名后Meta)、谷歌、Dell、华为、思科、微软、HPE最初的八巨头&#xff0c;发布了新的互联协议CXL&#xff0c;全称Comupte Express Link。由于在服务器领域享有绝对领导地位&#xff0c;Intel一经号令&#xf…

力扣-路径总和问题

路径总和 --简单 112. 路径总和 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 f…

在网络攻击之前、期间和之后应采取的步骤

在当今复杂的威胁形势下&#xff0c;网络攻击是不可避免的。 恶意行为者变得越来越复杂&#xff0c;出于经济动机的攻击变得越来越普遍&#xff0c;并且每天都会发现新的恶意软件系列。 这使得对于各种规模和跨行业的组织来说&#xff0c;制定适当的攻击计划变得更加重要。 …

Python大数据之linux学习总结——day10_hive调优

hive调优 hive调优hive命令和参数配置1.hive数据压缩压缩对比开启压缩 2.hive数据存储[练习]行列存储原理存储压缩比拓展dfs -du -h 3. fetch抓取4. 本地模式5. join的优化操作6. 列裁剪7. 分区裁剪8. group by 操作9. count(distinct)10. 笛卡尔积11. 动态分区[练习]12. 如何调…

Run Legends将健身运动游戏化,使用户保持健康并了解Web3游戏

最近&#xff0c;我们有机会采访Talofa Games的首席执行官兼创始人Jenny Xu&#xff0c;一起讨论游戏开发&#xff0c;Talofa Games是Run Legends这款健身游戏的开发工作室。她已经创作了超过一百款游戏&#xff0c;对于推动游戏的可能性并将她的创造力和叙事技巧带入她最喜爱的…

原理Redis-ZipList

ZipList 1) ZipList的组成2) ZipList的连锁更新问题3) 总结 1) ZipList的组成 ZipList 是一种特殊的“双端链表” &#xff0c;由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作, 并且该操作的时间复杂度为 O(1)。 ZipListEntry: ZipList 中的Entry并不像…

LangChain 5易速鲜花内部问答系统

展示了一个完整的问答系统的实现&#xff0c;使用了Flask来构建Web界面、langchain进行文档处理和检索&#xff0c;以及OpenAI的语言模型。代码的复杂性在于集成了多种高级技术和处理大型数据集和语言模型。 LangChain 实现给动物取名字&#xff0c;LangChain 2模块化prompt t…

linux 服务器进程、端口查找,nginx 配置日志查找,lsof 命令详解

一 、根据端口号 查看文件的部署位置 1.1 使用查看端口号对应的进程信息 方式一 &#xff1a; 使用netstat命令 netstat -tuln | grep 端口号-t&#xff1a;显示TCP连接 -u&#xff1a;显示UDP连接 -l&#xff1a;仅显示监听状态的连接 -n&#xff1a;以数字形式显示端口…

60 权限提升-MYMSORA等SQL数据库提权

目录 数据库应用提权在权限提升中的意义WEB或本地环境如何探针数据库应用数据库提权权限用户密码收集等方法目前数据库提权对应的技术及方法等 演示案例Mysql数据库提权演示-脚本&MSF1.UDF提权知识点: (基于MYSQL调用命令执行函数&#xff09;读取数据库存储或备份文件 (了…

几个强力的nodejs库

几个强力的nodejs库 nodejs被视为许多Web开发人员的理想运行时环境。 nodejs的设计是为了在运行时中使用JavaScript编写的代码&#xff0c;它是世界上最流行的编程语言之一&#xff0c;并允许广泛的开发者社区构建服务器端应用程序。 nodejs提供了通过JavaScript库重用代码的…

debian10 开启rdp安装firefox,firefox 中文乱码

debian10 开启rdp安装firefox apt -y install tigervnc-standalone-server apt -y install xrdp tigervnc-standalone-server systemctl enable xrdpapt install firefox-esrmstsc连接 firefox-settings-general-fonts-advanced-Simplified Chinese