• ES6,ES7,ES8 常用特性总结


    一. ES6(ES2015)

    1. 变量 let 和常量 const

    • var 的问题

      • 可以重复声明,没有报错和警告
      • 无法限制修改
      • 没有块级作用域, { }
    • let 和 const

      • 不能重复声明
      • 都是块级作用域, { } 块内声明的,块外无效
      • let 是变量,可以修改
      • const 是常量,不能修改
    • 块级作用域举例

      • 原来用 var 的方式,结果弹出的都是 3
      • 或者将变量 封装到函数里,限制作用域,但比较麻烦
      • 用 let 最简单,直接 var 改 let,解决作用域问题
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script>
            window.onload= function () {
                /*
                var aBtn = document.getElementsByTagName('input')
                for (var i=0; i < aBtn.length; i++) {
                    aBtn[i].onclick = function () {
                        alert(i)
                    }
                }*/
                var aBtn = document.getElementsByTagName('input')
                for (let i = 0; i < aBtn.length; i++) {
                    aBtn[i].onclick = function () {
                        alert(i)
                    }
                }
                /*
                var aBtn = document.getElementsByTagName('input')
                for (var i = 0; i < aBtn.length; i++) {
                    // 封装到函数里,限制作用域
                    (function (i) {
                        aBtn[i].onclick = function () {
                            alert(i)
                        }
                    })(i)
                }*/
            }
        </script>
    </head>
    <body>
        <input type="button" value="按钮1">
        <input type="button" value="按钮2">
        <input type="button" value="按钮3">
    </body>
    </html>

    2. 箭头函数

    引入箭头函数有两个方面的作用:简化函数和不需要绑定 this

    x => x * x
    上面的箭头函数相当于:
    
    function (x) {
        return x * x;
    }

    箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }return

    x => {
        if (x > 0) {
            return x * x;
        }
        else {
            return - x * x;
        }
    }

    如果参数不是一个,就需要用括号()括起来:

    // 两个参数:
    (x, y) => x * x + y * y
    
    // 无参数:
    () => 3.14
    
    // 可变参数:
    (x, y, ...rest) => {
        var i, sum = x + y;
        for (i=0; i<rest.length; i++) {
            sum += rest[i];
        }
        return sum;
    }

    如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:

    // SyntaxError:
    x => { foo: x }
    因为和函数体的{ ... }有语法冲突,所以要改为:
    
    // ok:
    x => ({ foo: x })

    箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。

    回顾前面的例子,由于JavaScript函数对this绑定的错误处理,下面的例子无法得到预期结果:

    var obj = {
        birth: 1990,
        getAge: function () {
            var b = this.birth; // 1990
            var fn = function () {
                return new Date().getFullYear() - this.birth; // this指向window或undefined
            };
            return fn();
        }
    };

    现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj

    var obj = {
        birth: 1990,
        getAge: function () {
            var b = this.birth; // 1990
            var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
            return fn();
        }
    };
    obj.getAge(); // 25

    如果使用箭头函数,以前的那种hack写法:

    var that = this;
    

    就不再需要了。

    由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:

    var obj = {
        birth: 1990,
        getAge: function (year) {
            var b = this.birth; // 1990
            var fn = (y) => y - this.birth; // this.birth仍是1990
            return fn.call({birth:2000}, year);
        }
    };
    obj.getAge(2015); // 25

    3. ...扩展参数符

    • 参数扩展/展开 ...args
      • 收集剩余的参数,必须当到最后一个参数位置
      • 展开数组,简写,效果和直接把数组的内容写在这儿一样
    • 默认参数
    function show(a, b, ...args) {
        console.log(a)        //  1
        console.log(b)       //  2
        console.log(args)      // [3,4,5]
    }
    show(1, 2, 3, 4, 5)
    
    let arr1 = [1, 2, 3]
    let arr2 = [4, 5, 6]
    let arr3 = [...arr1, ...arr2]
    console.log(arr3)        // [1,2,3,4,5,6]
    
    function show2(a, b=5, c=8) {
        console.log(a, b, c)  // 88 12 8
    }
    show2(88, 12)

    4. 解构赋值

    解构赋值

    • 左右两个边结构必须一样
    • 右边必须是个东西
    • 声明和赋值赋值不能分开,必须在一句话里

    数组:

    let [a, b, c] = [1, 2, 3];
    //等同于
    let a = 1;
    let b = 2;
    let c = 3;

    对象:

    var {
      StyleSheet,
      Text,
      View
    } = React;
    
    等同于
    var StyleSheet = React.StyleSheet;
    var Text = React.Text;
    var View = React.Text;

    获取对象中的值:

    const student = {
          name: 'bahg',
          age: 18,
          sex: 'girl'
        }
    const {name, age, sex} = student
    console.log(name); // bahg
    console.log(age);  // 18
    console.log(sex);  // girl

    5. 新增四个方法 map、reduce、filter、forEach

    (1)map映射 (一对一,返回新数组)

    let arr = [12, 5, 8]
    let result1 = arr.map(item=>item*2) // 简写
    console.log(result1)  // [ 24, 10, 16 ]
    
    let score = [18, 86, 88, 24]
    let result2 = score.map(item => item >= 60 ? '及格' : '不及格')
    console.log(result2)  // [ '不及格', '及格', '及格', '不及格' ]
    
    var users = [
      {name: "张XX",  "email": "zhang@email.com"},
      {name: "江XX",  "email": "jiang@email.com"},
      {name: "李XX",  "email": "li@email.com"}
    ];
    var emails = users.map(function (user) { return user.email; });
    console.log(emails.join(","));  // zhang@email.com, jiang@email.com, li@email.com

    (2)reduce 汇总(多变一,返回新数组)

    arr.reduce(function(prev,cur,index,arr){
       ...
    }, init);
    • prev    表示上一次调用回调时的返回值,或者初始值 init;
    • cur      表示当前正在处理的数组元素;
    • index  表示当前正在处理的数组元素的索引,若提供 init 值,则索引为0,否则索引为1;
    • arr       表示原数组;
    • init      表示初始值

    其实必需以及常用的参数只有两个:prev 和 cur。接下来我们跟着实例来看看具体用法吧~

    请参考 https://www.cnblogs.com/cckui/p/9267542.htmlhttps://www.cnblogs.com/amujoe/p/11376940.html

    (3)filter 过滤器(保留为true的,返回新数组)

    var arr = [12, 4, 8, 9]
    var result = arr.filter(item => (item % 3 === 0) ? true : false)
    console.log(result)  // Array(2)
    var result = arr.filter(item => item % 3 === 0)
    console.log(result)  // Array(2)
    
    var arr = [
        { title: '苹果', price: 10 },
        { title: '西瓜', price: 20 },
    ]
    var result = arr.filter(json => json.price >= 20)
    console.log(result)  // Array(1)

    (4)forEach 循环迭代(用于遍历数组,无返回值)

    var arr = [12, 4, 8, 9]
    var result = arr.forEach(item => console.log(item))
    var result = arr.forEach((item, index)=>console.log(item, index))

    注意:除了reduce方法之外的其他三个方法,都传入了一个匿名函数作为参数,而该匿名函数实际含有三个参数(我们这里只写了一个)。其依次代表数组遍历时的当前元素item,数组遍历时的当前元素的索引index,以及正在遍历的数组array。有了这三个参数,可以方便我们做很多事情,比如说将每一项数组元素翻倍,这时需要用到第一个参数item。但是,仅仅只是将item乘以2可不行,我们还得将其赋值给原来的数组,这时我们就得用到后面两个参数index和array。根据上述可知,array[index]是全等于item的。

    此外,这三个方法除了传递一个匿名函数作为参数之外,还可以传第二个参数,该参数用于指定匿名函数内的this指向,例如:

    // 只传一个匿名函数
    arr.forEach(function(item,index,array){
        console.log(this);  // window
    });
    // 传两个参数
    arr.forEach(function(item,index,array){
        console.log(this);  // [1, -2, 3, 4, -5]
    },arr);

    6. 字符串

    (1)模板字符串

    • 使用反引号,${变量}
    • 可以折行
     let a = 12
      let str1 = `asdf${a}`
      console.log(str1)  // asdf12
    
      let title = '标题'
      let content = '内容'
      let str = `<div>
        <h1>${title}</h1>
        <p>${content}</p>
    </div>`
      console.log(str)  

    <div>
      <h1>标题</h1>
      <p>内容</p>
    </div>

    (2)两个新方法

    startWith   endsWith

    var url = 'http://qq.com'
    console.log(url.startsWith('http'))
    console.log(url.endsWith('com'))
    // 都是 true

    7. 类

    • 原来写法
      • 类和构造函数一样
      • 属性和方法分开写的
    // 老版本
    function User(name, pass) {
        this.name = name
        this.pass = pass
    }
    
    User.prototype.showName = function () {
        console.log(this.name)
    }
    User.prototype.showPass = function () {
        console.log(this.pass)
    }
    
    var u1 = new User('able', '1233')
    u1.showName()
    u1.showPass()
    

    // 老版本继承 function VipUser(name, pass, level) { User.call(this, name, pass) this.level = level } VipUser.prototype = new User() VipUser.prototype.constructor = VipUser VipUser.prototype.showLevel = function () { console.log(this.level) } var v1 = new VipUser('blue', '1234', 3) v1.showName() v1.showLevel()
    • 新版面向对象
      • 有了 class 关键字、构造器
      • class 里面直接加方法
      • 继承,super 超类==父类
    class User {
        constructor(name, pass) {
            this.name = name
            this.pass = pass
        }
    
        showName() {
            console.log(this.name)
        }
        showPass() {
            console.log(this.pass)
        }
    }
    
    var u1 = new User('able2', '111')
    u1.showName()
    u1.showPass()
    
    // 新版本继承
    class VipUser extends User {
        constructor(name, pass, level) {
            super(name, pass)
            this.level = level
        }
        showLevel(){
            console.log(this.level)
        }
    }
    
    v1 = new VipUser('blue', '123', 3)
    v1.showLevel()

    8. 模块化

    ES5 不支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。模块的功能主要由 export 和 import 组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过 export 来规定模块对外暴露的接口,通过 import 来引用其他模块提供的接口。同时还为模板创造了命名空间,防止函数的命名冲突。

    导出(export)导入 (import)

    ES6 允许在一个模块 export 来导出多个变量或函数。定义好模块的输出以后就可以在另外一个模块通过 import 引入。

    导出变量:

    export var name = 'bahg'       // 导出变量
    export const sqrt = Math.sqrt  // 导出常量
    export {name, sqrt} // 批量导出

    导入变量:

    import {name, age} from '...'

    导出函数:

    export function sum(a, b){
        return (a + b)
    }

    导入函数:

    import {sum} from '...'

    9. Promise

    • 异步和同步

      • 异步,操作之间没有关系,同时执行多个操作, 代码复杂
      • 同步,同时只能做一件事,代码简单
    • Promise 对象

      • 用同步的方式来书写异步代码
      • Promise 让异步操作写起来,像在写同步操作的流程,不必一层层地嵌套回调函数
      • 改善了可读性,对于多层嵌套的回调函数很方便
      • 充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口
    • Promise 也是一个构造函数

      • 接受一个回调函数f1作为参数,f1里面是异步操作的代码
      • 返回的p1就是一个 Promise 实例
      • 所有异步任务都返回一个 Promise 实例
      • Promise 实例有一个then方法,用来指定下一步的回调函数
    function f1(resolve, reject) {
      // 异步代码...
    }
    var p1 = new Promise(f1);
    p1.then(f2); // f1的异步操作执行完成,就会执行f2。
    Promise 使得异步流程可以写成同步流程
    // 传统写法
    step1(function (value1) {
      step2(value1, function(value2) {
        step3(value2, function(value3) {
          step4(value3, function(value4) {
            // ...
          });
        });
      });
    });
    
    // Promise 的写法
    (new Promise(step1))
      .then(step2)
      .then(step3)
      .then(step4);
    • Promise.all(promiseArray)方法
      • 将多个Promise对象实例包装,生成并返回一个新的Promise实例
      • promise数组中所有的promise实例都变为resolve的时候,该方法才会返回
      • 并将所有结果传递results数组中
      • promise数组中任何一个promise为reject的话,则整个Promise.all调用会立即终止,并返回一个reject的新的promise对象
    var p1 = Promise.resolve(1),
        p2 = Promise.resolve(2),
        p3 = Promise.resolve(3);
    Promise.all([p1, p2, p3]).then(function (results) {
        console.log(results);  // [1, 2, 3]
    });
    • Promise.race([p1, p2, p3])
      • Promse.race就是赛跑的意思
      • 哪个结果获得的快,就返回那个结果
      • 不管结果本身是成功状态还是失败状态

    二. ES7 新特性(ES2016)

    1. Array.prototype.includes

    它是一个替代 indexOf,开发人员用来检查数组中是否存在值,indexOf 是一种尴尬的使用,因为它返回一个元素在数组中的位置,如果没有这个元素则返回 -1。它返回的是一个数字,而不是一个布尔值。开发人员需要实施额外的检查。在ES6,要检查是否存在值你需要做一些如下图所示小技巧,因为他们没有匹配到值,Array.prototype.indexOf 返回- 1变成了true(转换成true),但是当匹配的元素为0位置时候,该数组包含元素,却变成了false。例如:

    let arr = ['react', 'angular', 'vue']
    
    // WRONG
    if (arr.indexOf('react')) { // 0 -> evaluates to false, definitely as we expected
      console.log('Can use React') // this line would never be executed
    }
    
    // Correct
    if (arr.indexOf('react') !== -1) {
      console.log('Can use React')
    }

    然而在 ES7 中:

    let arr = ['react', 'angular', 'vue']
      console.log(arr.includes('vue'))  // true
    // Correct
    if (arr.includes('react')) {
      console.log('Can use React')
    }

    还能在字符串中使用 includes:

    let str = 'React Quickly'
    
    // Correct
    if (str.toLowerCase().includes('react')) {  // true
      console.log('Found "react"')  
    }

    includes也可以在NaN(非数字)使用。最后 ,includes第二可选参数fromIndex,这对于优化是有好处的,因为它允许从特定位置开始寻找匹配。更多例子:

    console.log([1, 2, 3].includes(2)) // === true)
    console.log([1, 2, 3].includes(4)) // === false)
    console.log([1, 2, NaN].includes(NaN)) // === true)
    console.log([1, 2, -0].includes(+0)) // === true)
    console.log([1, 2, +0].includes(-0)) // === true)
    console.log(['a', 'b', 'c'].includes('a')) // === true)
    console.log(['a', 'b', 'c'].includes('a', 1)) // === false)

    2. Exponentiation Operator(求幂运算)

    求幂运算大多数是做一些数学计算,对于3D,VR,SVG还有数据可视化非常有用。在ES6或者早些版本,不得不创建一个循环,创建一个递归函数或者使用 Math.pow

    在 ES6 中,可以使用 Math.pow 创建一个短的递归箭头函数:

    calculateExponent = (base, exponent) => base*((--exponent>1)?calculateExponent(base, exponent):base)
    console.log(calculateExponent(7,12) === Math.pow(7,12)) // true
    console.log(calculateExponent(2,7) === Math.pow(2,7)) // true

    然而在 ES7 中:

    let a = 7 ** 12
    let b = 2 ** 7
    console.log(a === Math.pow(7,12)) // true
    console.log(b === Math.pow(2,7)) // true
    
    let a = 7
    a **= 12
    let b = 2
    b **= 7
    console.log(a === Math.pow(7,12)) // true
    console.log(b === Math.pow(2,7)) // true

    三. ES8 新特性(ES2017)

    1. Object.values()

    Object.values() 是一个与 Object.keys() 类似的新函数,但返回的是 Object 自身属性的所有值,不包括继承的值。

    假如要遍历如下对象 obj 的所有值:

    const obj = {a: 1, b: 2, c: 3}

    不使用 Object.values():ES7

    const vals = Object.keys(obj).map(key => obj[key])
    console.log(vals)

    使用 Object.values():ES8

    const vals = Object.values(obj)
    console.log(vals)

    从上述代码中可以看出 Object.values() 为我们省去了遍历 key,并根据这些 key 获得 value 的过程。

    2. Object.entries()

    Object.entries() 函数返回一个给定对象自身可枚举属性的键值对的数组。

    下面我们来遍历上文中 obj 对象的所有属性的 key 和 value:

    不使用 Object.values():ES7

    Object.keys(obj).forEach(key => {
        console.log('key:' + key + ' value:' + obj[key])
    })

    使用 Object.values():ES8

    for(let [key, value] of Object.entries(obj)) {
      console.log(`key:${key} value:${value}`)  
    }

    3. String padding(字符串填充)

    (1)String.prototype.padStart

    padStart()在开始部位填充,返回一个给出长度的字符串,填充物给定字符串,把字符串填充到期望的长度。从字符串的左边开始(至少大部分西方语言),一个经典例子是使用空格创建列:

    console.log('react'.padStart(10).length)         // "       react" is 10
    console.log('backbone'.padStart(10).length)     // "  backbone" is 10

    它对于财务方面非常有用:

    console.log('0.00'.padStart(20))            
    console.log('10,000.00'.padStart(20))    
    console.log('250,000.00'.padStart(20)) 
    如果是为会计做账之类的,这个很实用,帐做的很整齐
             0.00
        10,000.00
       250,000.00    

    (2)String.prototype.padEnd

    padEnd顾名思义就是才能够字符串的尾端右边开始填充。第二个参数,实际上可以用任何长度的字符串。例如:

    console.log('react'.padEnd(10, ':-)'))         // "react:-):-" is 10
    console.log('backbone'.padEnd(10, '*'))         // "backbone**" is 10

    在赏几个例子作为总结:

    // String.prototype.padStart(targetLength [, padString])
    'hello'.padStart(10); // '     hello'
    'hello'.padStart(10, '0'); // '00000hello'
    'hello'.padStart(); // 'hello'
    'hello'.padStart(6, '123'); // '1hello'
    'hello'.padStart(3); // 'hello'
    'hello'.padStart(3, '123'); // 'hello';
    
    // String.prototype.padEnd(targetLength [, padString])
    'hello'.padEnd(10); // 'hello     '
    'hello'.padEnd(10, '0'); // 'hello00000'
    'hello'.padEnd(); // 'hello'
    'hello'.padEnd(6, '123'); // 'hello1'
    'hello'.padEnd(3); // 'hello'
    'hello'.padEnd(3, '123'); // 'hello';

    4. Object.getOwnPropertyDescriptors

    该函数用来获取一个对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。

    const obj = {
         name: 'bahg',
         get age() {
           return '18'
         }
       };
      console.log(Object.getOwnPropertyDescriptor(obj, "name"))
      console.log(Object.getOwnPropertyDescriptor(obj, "age"))
    
    打印结果:
     
    1. {value: "bahg", writable: true, enumerable: true, configurable: true}
      1. configurabletrue
      2. enumerabletrue
      3. value"bahg"
      4. writabletrue
      5. __proto__Object
    
    
    {set: undefined, enumerable: true, configurable: true, get: ƒ}configurable: trueenumerable: trueget: ƒ age()set: undefined__proto__: Object

    5. 函数参数列表结尾允许逗号

    6. 异步函数 async/await

    async function show() {
        console.log(1)
        await
        console.log(2)
    }
      异步函数(或者async/await)特性操作是Promise最重要的功能。这种想法是为了在写异步代码中简化它,因为人类大脑最讨厌这种平行非序号思维了。它只是不会演变这种方式。本来以为Promise的到来已经是摆脱node异步的福音了,在ES8,异步函数是那么给力。开发者定义一个asyc函数里面不包含或者包含 await 基于Promise异步操作。在这引擎之下一个异步函数返回一个Promise,无论无何你在任何地方不会看到这样的一个词Promise。例如,在ES6中我们可以使用Promise,Axios库向GraphQL服务器发送一个请求:
    axios.get(`/q?query=${query}`)
      .then(response => response.data)
      .then(data => {
        this.props.processfetchedData(data) // Defined somewhere else
      })
      .catch(error => console.log(error))
    任何一个Promise库都能兼容新的异步函数,我们可以使用同步try/catch做错误处理
    async fetchData(url) => {
      try {
        const response = await axios.get(`/q?query=${query}`)
        const data = response.data
        this.props.processfetchedData(data)
      } catch (error) {
        console.log(error)
      }
    }
    异步函数返回一个Promise,所以我们像下面可以继续执行流程:
    async fetchData(query) => {
      try {
        const response = await axios.get(`/q?query=${query}`)
        const data = response.data
        return data
      } catch (error) {
        console.log(error)
      }
    }
    fetchData(query).then(data => {
      this.props.processfetchedData(data)
    })

    本文参考 https://www.cnblogs.com/blueball/p/12409085.html

  • 相关阅读:
    初入angularJS [2]
    初入angularJS [1]
    ubuntu13.10 nginx
    Session对象详解[源于网络]
    二、Python变量
    一、计算机硬件及操作系统
    python进阶之装饰器之3如何利用装饰器强制函数上的类型检查
    python基础之闭包函数
    python进阶之装饰器之2.定义一个可接受参数的装饰器、如何定义一个属性可由用户修改的装饰器、定义一个能接受可选参数的装饰器
    python进阶之装饰器之1.如何定义一个基本的装饰器并使用,保留装饰器的元数据(原信息),逆向解得函数原信息
  • 原文地址:https://www.cnblogs.com/BAHG/p/12890211.html
Copyright © 2020-2023  润新知