ES6 新特性

作者: 陌盍 | 来源:发表于2019-02-20 18:18 被阅读133次

    一、let 和 const 命令

    • let命令: 用于声明对象,用法类似于var,但是 let 所声明的变量只在let命令所在的代码块内有效
    {
      var a = 1;
      let b = 2;
    }
    console.log(a);     // 1
    console.log(b);     // 报错  Uncaught ReferenceError: b is not defined
    
    • const命令: 声明一个只读的常量,一旦声明,常量的值就不能改变,这也意味着,const一旦声明变量,就必须立即初始化,不能以后再赋值。且constlet的作用域相同,只在声明所在的块级作用域内有效
    const c = 10;
    c;     // 10
    c= 100;     // 报错 Uncaught TypeError: Assignment to constant variable.
    
    if(true) {
        const d = 5;
    }
    console.log(d);    // 报错 ReferenceError: d is not defined
    
    • 特点:
      1.letconst 命令声明的变量都不存在变量提升,即其声明的变量一定要在声明后使用,否则报错;
      2.都存在暂时性死区,即只要块级作用域内存在letconst命令,它所声明的变量就“绑定”这个区域,不再受外部的影响。
    var tmp = 111;
    if (true) {
        tmp = 'abc';    // 报错   ReferenceError: tmp is not defined
        let tmp = 5;
    }
    

    二、解构赋值

    ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

    1.数组的解构赋值
    • 模式匹配:只要等号两边的模式相同,左边的变量就会被赋予对应的值。
    let [a, b, c] = [1, 2, 3];
    console.log(a, b, c);     // 1   2   3
    
    • 使用嵌套数组进行解构
    let [foo, [[bar], baz]] = [1, [[2], 3]];
    foo // 1
    bar // 2
    baz // 3
    
    let [ , , third] = ["foo", "bar", "baz"];
    third // "baz"
    
    let [x, , y] = [1, 2, 3];
    x // 1
    y // 3
    
    let [head, ...tail] = [1, 2, 3, 4];
    head // 1
    tail // [2, 3, 4]
    
    let [x, y, ...z] = ['a'];
    x // "a"
    y // undefined
    z // []
    

    如果解构不成功,变量的值就等于 undefined

    let [foo] = [];
    let [bar, foo] = [1];
    //  以上两种情况都属于解构不成功,foo的值都会等于undefined
    
    • 不完全解构:即等号左边的模式,只匹配一部分的等号右边的数组,这种情况下,解构依然可以成功。
    let [x, y] = [1, 2, 3];
    x // 1
    y // 2
    
    let [a, [b], d] = [1, [2, 3], 4];
    a // 1
    b // 2
    d // 4
    
    2.对象的解构赋值

    对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

    let { bar, foo } = { foo: "aaa", bar: "bbb" };
    foo // "aaa"
    bar // "bbb"
    //  等号左边的两个变量的次序,与等号右边两个同名属性的次序不一致,但是对取值完全没有影响
    let { baz } = { foo: "aaa", bar: "bbb" };
    baz // undefined     变量没有对应的同名属性,导致取不到值,最后等于undefined
    

    如果变量名与属性名不一致,必须写成下面这样:

    let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
    baz // "aaa"
    foo // error: foo is not defined
    
    let obj = { first: 'hello', last: 'world' };
    let { first: f, last: l } = obj;
    f // 'hello'
    l // 'world'
    

    也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。上面第一个例子,foo是匹配的模式,baz才是变量,真正被赋值的是变量baz,而不是模式foo。

    3.字符串的解构赋值

    字符串也可以解构赋值,此时,字符串被转换成了一个类似数组的对象。

    const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"
    

    类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

    let {length : len} = 'hello';
    len // 5
    

    三、Iterator(遍历器) 和 for...of 循环

    遍历器(Iterator)是一种用来统一处理所有不同数据结构的接口机制,为各种不同的数据结构提供统一的访问机制。遍历器有三个作用,一是为各种数据结构提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for...of循环,遍历器Iterator 接口主要供for...of消费。

    var a = ['A', 'B', 'C'];
    var b = new Set(['A', 'B', 'C']);
    var c = new Map([[1, 'A'], [2, 'B'], [3, 'C']]);
    for (var x of a) { // 遍历Array
        console.log(x);    //   A  B  C
    }
    for (var x of b) { // 遍历Set
        console.log(x);      // A  B  C
    }
    for (var x of c) { // 遍历Map
        console.log(x[0] + '=' + x[1]);    // 1=A   2=B   3=C
    }
    

    四、箭头函数

    ES6 允许使用“箭头”(=>)定义函数。如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

    var f = () => 5;    // 函数不需要参数
    // 等同于
    var f = function () { return 5 };
    
    var sum = (num1, num2) => num1 + num2;   // 函数需要多个参数
    // 等同于
    var sum = function(num1, num2) {
      return num1 + num2;
    };
    

    使用注意点

    • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
    • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
    • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
    • 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

    说明:箭头函数没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。

    五、模板字符串

    模板字符串(template string)是增强版的字符串,用反引号(``)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中用${变量名}的方式嵌入变量。

    使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。比如<ul>标签前面会有一个换行。如果你不想要这个换行,可以使用trim方法消除它。

    $('#list').html(`
    <ul>
      <li>first</li>
      <li>second</li>
    </ul>
    `.trim());
    

    六、Promise对象

    Promise 是异步编程的一种解决方案,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

    Promise状态pending(进行中)、fulfilled(已成功)和rejected(已失败)

    Promise特点:

    • 对象的状态不受外界影响,Promise对象代表一个异步操作,只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态;
    • 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。

    Promise优缺点

    • 有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
    • Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

    Promise 新建后立即执行,所以首先输出的是 Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

    let promise = new Promise(function(resolve, reject) {
      console.log('Promise');
      resolve();
    });
    
    promise.then(function() {
      console.log('resolved.');
    });
    
    console.log('Hi!');
    // 依次打印:Promise   Hi   resolved
    

    下面用Promise对象实现Ajax操作:

    const getJSON = function(url) {
      const promise = new Promise(function(resolve, reject){
        const handler = function() {
          if (this.readyState !== 4) {
            return;
          }
          if (this.status === 200) {
            resolve(this.response);
          } else {
            reject(new Error(this.statusText));
          }
        };
        const client = new XMLHttpRequest();
        client.open("GET", url);
        client.onreadystatechange = handler;
        client.responseType = "json";
        client.setRequestHeader("Accept", "application/json");
        client.send();
    
      });
    
      return promise;
    };
    
    getJSON("/posts.json").then(function(json) {
      console.log('Contents: ' + json);
    }, function(error) {
      console.error('出错了', error);
    });
    

    七、Class 类

    ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法。

    // js 中生成实例对象的传统方法是通过构造函数
    function Point(x, y) {
      this.x = x;
      this.y = y;
    }
    Point.prototype.toString = function () {
      return '(' + this.x + ', ' + this.y + ')';
    };
    var p = new Point(1, 2);
    
    //  ES6 的class改写上面代码:定义一个“类”,里面一个constructor方法,这就是构造方法,而this关键字则代表实例对象
    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    }
    

    生成类的实例的写法,与 ES5 完全一样,也是使用new命令,实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。

    //定义类
    class Point {
    
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    
    }
    
    var point = new Point(2, 3);
    
    point.toString() // (2, 3)
    
    point.hasOwnProperty('x') // true
    point.hasOwnProperty('y') // true
    point.hasOwnProperty('toString') // false
    point.__proto__.hasOwnProperty('toString') // true
    

    Class 可以通过extends关键字实现继承

    class ColorPoint extends Point {
      constructor(x, y, color) {
        super(x, y);  // 调用父类的constructor(x, y)
        this.color = color;
      }
      toString() {
        return this.color + ' ' + super.toString();  // 调用了父类的toString()
      }
    }
    

    上面代码定义了一个ColorPoint类,该类通过extends关键字,继承了Point类的所有属性和方法。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。

    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    }
    class ColorPoint extends Point {
      constructor(x, y, color) {
        this.color = color; // ReferenceError
        super(x, y);
        this.color = color; // 正确
      }
    }
    

    上面代码中,子类的constructor方法没有调用super之前,就使用this关键字,结果报错,而放在super方法之后就是正确的。

    相关文章

      网友评论

        本文标题:ES6 新特性

        本文链接:https://www.haomeiwen.com/subject/waphyqtx.html