zoukankan      html  css  js  c++  java
  • ES7及ES8新特性

    ES7新特性

    (ECMAScript2016 新特性)

    一、Array

    1、Array.prototype.includes

    includes()的作用,是查找一个值在不在数组里,若在,则返回true,反之返回false。 基本用法:

    ['a', 'b', 'c'].includes('a')     // true
    ['a', 'b', 'c'].includes('d')     // false
    

    Array.prototype.includes()方法接收两个参数:要搜索的值和搜索的开始索引。当第二个参数被传入时,该方法会从索引处开始往后搜索(默认索引值为0)。若搜索值在数组中存在则返回true,否则返回false。

    ['a', 'b', 'c', 'd'].includes('b')         // true
    ['a', 'b', 'c', 'd'].includes('b', 1)      // true
    ['a', 'b', 'c', 'd'].includes('b', 2)      // false
    

    那么,我们会联想到ES6里数组的另一个方法indexOf,下面的示例代码是等效的:

    ['a', 'b', 'c'].includes('a')          //true
    ['a', 'b', 'c'].indexOf('a') > -1      //true
    

    注意:

    (1)使用的都是 === 操作符来做值的比较。但是includes()方法有一点不同,两个NaN被认为是相等的,即使在NaN === NaN结果是false的情况下,indexOf()严格使用===判断。

    let demo = [1, NaN, 2, 3]
    
    demo.indexOf(NaN)        //-1
    demo.includes(NaN)       //true
    

    (2)includes()还有一个怪异的点需要指出,在判断 +0 与 -0 时,被认为是相同的。在这一点上,indexOf()与includes()的处理结果是一样的,同样会返回 +0 的索引值。

    [1, +0, 3, 4].includes(-0)    //true
    [1, +0, 3, 4].indexOf(-0)     //1
    

    二、求幂运算符

    ** 是一个用于求幂的中缀算子。

    3 ** 2                      // 9
    

    等同于

    Math.pow(3, 2)              // 9
    

    比较可知,中缀符号比函数符号更简洁,这也使得它更为可取。

    既然说**是一个运算符,那么它就应该能满足类似加等的操作,我们姑且称之为幂等,例如下面的例子,a的值依然是9:

    let a = 3;
    a **= 2;
    // 9
    

    ES8新特性

    (ECMAScript2017 新特性)

    一、String

    1、新增 String.prototype.padStart 和 String.prototype.padEnd 两个函数,用于在字符串开头或结尾添加填充字符串。函数的声明如下:

    String.prototype.padStart( maxLength [ , fillString ] )
    String.prototype.padEnd( maxLength [ , fillString ] )
    

    其中第一个参数是目标长度;第二个参数是填充字符串,默认是空格。

    示例:

    'es8'.padStart(2);              // 'es8'
    'es8'.padStart(5);              // '  es8'
    'es8'.padStart(6, 'woof');      // 'wooes8'
    'es8'.padStart(14, 'wow');      // 'wowwowwowwoes8'
    'es8'.padStart(7, '0');         // '0000es8'
    
    'es8'.padEnd(2);                // 'es8'
    'es8'.padEnd(5);                // 'es8  '
    'es8'.padEnd(6, 'woof');        // 'es8woo'
    'es8'.padEnd(14, 'wow');        // 'es8wowwowwowwo'
    'es8'.padEnd(7, '6');           // 'es86666'
    
    典型的应用场景

    (1)使用 padStart 进行时间格式化。

    '8:00'.padStart(5, '0');                // '08:00'
    '18:00'.padStart(5, '0');               // '18:00'
    '12'.padStart(10, 'YYYY-MM-DD')         // "YYYY-MM-12"
    '09-12'.padStart(10, 'YYYY-MM-DD')      // "YYYY-09-12"
    

    (2)使用 padStart 给命令行输出信息对齐。

    Commands:
    
      run       Start a front service
      start     Start a background service
      stop      Stop current background service
      restart   Restart current background service
      help      Display help information
    

    二、Object

    Object.values & Object.entries 是对 Object.keys() 的补充。

    const obj = { 
        x: 'xxx', 
        y: 1 
    };
    Object.keys(obj);       // ['x', 'y']
    

    1、Object.values

    静态方法 Object.values() 获取对象的所有可遍历属性的值,返回一个数组。

    (1)基本用法

    const obj = { 
        x: 'xxx', 
        y: 1 
    };
    Object.values(obj);     // ['xxx', 1]
    

    (2)数组可以看做键为下标的对象

    // ['e', 's', '8'] -> { 0: 'e', 1: 's', 2: '8' }
    const obj = ['e', 's', '8'];
    Object.values(obj);     // ['e', 's', '8']
    

    (3)字符串可以看做键为下标的对象

    // 'es8' -> { 0: 'e', 1: 's', 2: '8' }
    Object.values('es8');   // ['e', 's', '8']
    

    (4)如果是纯 number 型的键值,则返回值顺序根据键值从小到大排列

    const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
    Object.values(obj);     // ['yyy', 'zzz', 'xxx']
    

    2、Object.entries

    静态方法 Object.entries 获取对象的所有可遍历属性的键值对,以 [key, value] 数组的形式返回,顺序和 Object.values() 一致。

    (1)基本用法

    const obj = { 
        x: 'xxx', 
        y: 1 
    };
    Object.entries(obj);    // [['x', 'xxx'], ['y', 1]]
    

    (2)数组可以看做键为下标的对象

    // ['e', 's', '8'] -> { 0: 'e', 1: 's', 2: '8' }
    const obj = ['e', 's', '8'];
    Object.entries(obj);    // [['0', 'e'], ['1', 's'], ['2', '8']]
    

    (3)字符串可以看做键为下标的对象

    // 'es8' -> { 0: 'e', 1: 's', 2: '8' }
    Object.entries('es8');      // [['0', 'e'], ['1', 's'], ['2', '8']]
    

    (4)如果是纯 number 型的键值,则返回值顺序根据键值从小到大排列

    const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
    Object.entries(obj);        // [['1', 'yyy'], ['3', 'zzz'], ['10': 'xxx']]
    

    3、扩展

    Object.keys(), Object.values(), Object.entries() 通常用来遍历一个对象,除了这三个方法外,常用的还有 for...in 和 for...of + Object.keys() 循环。

    使用 for...in 遍历

    const obj = { 
        x: 'xxx', 
        y: 1 
    };
    for (let key in obj) {
        console.log(key);
    }
    

    使用 for...of + Object.keys() 遍历

    const obj = { 
        x: 'xxx', 
        y: 1 
    };
    for (let key of Object.keys(obj)) {
        console.log(key);
    }
    

    上述例子中两种遍历方式等价。但在更复杂的情况下,这两种方式的结果会不一样。

    for...in 循环会遍历对象的可枚举属性,包括原型链上继承的属性,而 Object.keys() 不会遍历继承的属性。

    下面是一个继承的例子,Human 继承自 Animal。

    function Animal() {
        this.legs = 4;
    }
    function Human(name) {
        this.name = name;
    }
    Human.prototype = new Animal();
    let human = new Human('es8');
    

    使用 for...in 遍历

    for (let key in human) {
        console.log(key);           // 'name', 'legs'
    }
    

    使用 for...of + Object.keys() 遍历

    for (let key of Object.keys(human)) {
        console.log(key);           // 'name' 
    }
    

    4、Object.getOwnPropertyDescriptors

    静态方法 Object.getOwnPropertyDescriptors 用于获取对象的属性描述符,该属性必须是对象自己定义而不是继承自原型链。结果中包含的键可能有 configurable、enumerable、writable、get、set 以及 value。

    const obj = { es8: 'hello es8' };
    Object.getOwnPropertyDescriptor(obj, 'es8');
    // {
    //   configurable: true,
    //   enumerable: true,
    //   value: "hello es8"
    //   writable: true
    // }
    

    三、Trailing commas in function

    ES8 标准中允许函数参数列表与调用中的尾部逗号,该特性允许我们在定义或者调用函数时添加尾部逗号。

    function es8(var1, var2, var3,) {
        console.log(arguments.length);              // 3
    }
    es8(10, 20, 30,);
    

    四、Async functions

    JavaScript语言的执行环境是“单线程”的,那么异步编程对JavaScript语言来说就显得尤为重要。以前我们大多数的做法是使用回调函数来实现JavaScript语言的异步编程。回调函数本身没有问题,但如果出现多个回调函数嵌套,例如:进入某个页面,需要先登录,拿到用户信息之后,调取用户商品信息,代码如下:

    this.$http.jsonp('/login', (res) => {
        this.$http.jsonp('/getInfo', (info) => {
            // do something
        })
    })
    

    假如上面还有更多的请求操作,就会出现多重嵌套。代码很快就会乱成一团,这种情况就被称为“回调函数地狱”(callback hell)。

    于是,我们提出了Promise,它将回调函数的嵌套,改成了链式调用。写法如下:

    var promise = new Promise((resolve, reject) => {
        this.login(resolve)
    })
    .then(() => this.getInfo())
    .catch(() => { 
        console.log("Error") 
    })
    

    从上面可以看出,Promise的写法只是回调函数的改进,使用then方法,只是让异步任务的两段执行更清楚而已。Promise的最大问题是代码冗余,请求任务多时,一堆的then,也使得原来的语义变得很不清楚。此时我们引入了另外一种异步编程的机制:Generator。

    Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

    function* helloWorldGenerator() {
        yield 'hello';
        yield 'world';
        return 'ending';
    }
    
    var hw = helloWorldGenerator();
    

    上面代码定义了一个 Generator 函数 helloWorldGenerator, 它内部有两个 yield 表达式(hello和world),即该函数有三个状态:hello,world 和 return 语句(结束执行)。
    Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。上述代码分步执行如下:

    hw.next()
    // { value: 'hello', done: false }
    
    hw.next()
    // { value: 'world', done: false }
    
    hw.next()
    // { value: 'ending', done: true }
    
    hw.next()
    // { value: undefined, done: true }
    

    Generator函数的机制更符合我们理解的异步编程思想。

    用户登录的例子,我们用Generator来写,如下:

    var gen = function* () {
        const f1 = yield this.login()
        const f2 = yield this.getInfo()
    };
    

    虽然Generator将异步操作表示得很简洁,但是流程管理却不方便(即何时执行第一阶段、何时执行第二阶段)。此时,我们便希望能出现一种能自动执行Generator函数的方法。我们的主角来了:async/await。

    ES8引入了async函数,使得异步操作变得更加方便。简单说来,它就是Generator函数的语法糖。

    async function asyncFunc(params) {
        const result1 = await this.login()
        const result2 = await this.getInfo()
    }
    

    变体

    异步函数存在以下四种使用形式:

    • 函数声明
    async function foo() {}
    
    • 函数表达式
    const foo = async function() {}
    
    • 对象的方式
    let obj = { 
        async foo() {} 
    }
    
    • 箭头函数
    const foo = async () => {}
    

    常见用法汇总

    1、处理单个异步结果:

    async function asyncFunc() {
        const result = await otherAsyncFunc();
        console.log(result);
    }
    

    2、顺序处理多个异步结果:

    async function asyncFunc() {
        const result1 = await otherAsyncFunc1();
        console.log(result1);
        const result2 = await otherAsyncFunc2();
        console.log(result2);
    }
    

    3、并行处理多个异步结果:

    async function asyncFunc() {
        const [result1, result2] = await Promise.all([
            otherAsyncFunc1(),
            otherAsyncFunc2()
        ]);
        console.log(result1, result2);
    }
    

    4、处理错误:

    async function asyncFunc() {
        try {
            await otherAsyncFunc();
        } catch (err) {
            console.error(err);
        }
    }
    

    若想进一步了解async的具体实践,可参见阮一峰的博客文章,链接奉上:http://es6.ruanyifeng.com/#docs/async

    参考链接:https://segmentfault.com/a/1190000010213513
    https://www.cnblogs.com/zhuanzhuanfe/p/7493433.html

  • 相关阅读:
    Unity中 mesh生成斜坡
    设计模式
    Go语言高级编程
    Go语言高级编程
    agentzh 的 Nginx 教程(版本 2020.03.19)
    ubuntu18安装mysql5.7并配置远程连接
    创建图库
    交点修改
    显示中文
    浅谈前端水印
  • 原文地址:https://www.cnblogs.com/onesea/p/12862340.html
Copyright © 2011-2022 走看看