美文网首页
ECMAScript 6 新增内容

ECMAScript 6 新增内容

作者: wdapp | 来源:发表于2020-01-28 21:04 被阅读0次
    • 变量的扩展
      • let
      • const
      • 变量的结构
    • 字符串的扩展及新增方法
      • 模板字符串 (`${}`)
      • matchAll 方法返回一个正则表达式在当前字符串的所有匹配
      • includes 返回布尔值,表示是否找到了参数字符串。
      • repeat 方法返回一个新字符串,表示将原字符串重复n次。
      • trimStart 消除字符串头部的空格
      • trimEnd 消除尾部的空格
    • 数值的扩展
      • 指数运算符 (**)
      • Number.MAX_SAFE_INTEGER (2*53)
      • Number.MIN_SAFE_INTEGER (-2*53)
      • isSafeInteger 用来判断一个整数是否落在这个范围之内。
      • Math.trunc 方法用于去除一个数的小数部分,返回整数部分。
      • Math.sign 方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
      • Math.cbrt 方法用于计算一个数的立方根。
      • Math.imul 方法返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。
    • 函数扩展
      • name 属性
      • 函数参数的默认值
      • rest 参数
      • 箭头函数
      • 尾递归、尾部调用
    • 数组扩展
      • 扩展运算符 [...arr]
      • includes
      • keys、values、entries
      • flat、flatMap
    • 对象的扩展及新增方法
      • 属性的简洁表示法
      • getOwnPropertyDescriptor
      • super 指向当前对象的原型对象
      • Object.is
      • Object.assign
      • keys、values、entries、formEntries
      • setPropertyOf、getPropertyOf
    • Symbol
      • Symbol()
      • Symbol.for()
      • Symbol.keyFor()
      • 内置的 Symbol 值
    • Set 和 Map 数据结构
      • Set、WeakSet(成员只能是对象)
      • Map(键值对集合)、WeakMap(键只能是对象)
    • Proxy
    • Reflect
    • Promise
    • Iterator
    • Generator
    • async、await
    • Class
      • 静态属性
      • 静态方法
      • 实例属性的新写法
      • 私有方法
      • new.target 属性
      • 继承
      • 构造函数
      • super 关键字
    • Module
      • export
      • import

    尾调用优化

    function f() {
      let m = 1;
      let n = 2;
      return g(m + n);
    }
    f();
    
    // 等同于
    function f() {
      return g(3);
    }
    f();
    
    // 等同于
    g(3);
    
    ---
    
    // 不属于尾调用
    function addOne(a){
      var one = 1;
      function inner(b){
        return b + one;
      }
      return inner(a);
    }
    
    

    尾递归优化

    
    function factorial(n) {
      if (n === 1) return 1;
      return n * factorial(n - 1);
    }
    
    factorial(5) // 120
    
    ---
    
    // 尾递归优化
    function factorial(n, total) {
      if (n === 1) return total;
      return factorial(n - 1, n * total);
    }
    
    factorial(5, 1) // 120
    
    

    模块的 Singleton 模式

    // mod.js
    const FOO_KEY = Symbol.for('foo');
    
    function A() {
      this.foo = 'hello';
    }
    
    if (!global[FOO_KEY]) {
      global[FOO_KEY] = new A();
    }
    
    module.exports = global[FOO_KEY];
    
    const a = require('./mod.js');
    
    a.foo // 'hello'
    
    global[Symbol.for('foo')] = { foo: 'world' };
    
    const a = require('./mod.js');
    
    a.foo // 'world'
    

    内置的 Symbol 值

    // Symbol.hasInstance
    
    class MyClass {
      [Symbol.hasInstance](foo) {
        return foo instanceof Array;
      }
    }
    
    [1, 2, 3] instanceof new MyClass() // true
    
    class Even {
      static [Symbol.hasInstance](obj) {
        return Number(obj) % 2 === 0;
      }
    }
    
    // 等同于
    const Even = {
      [Symbol.hasInstance](obj) {
        return Number(obj) % 2 === 0;
      }
    };
    
    1 instanceof Even // false
    2 instanceof Even // true
    12345 instanceof Even // false
    
    // Symbol.isConcatSpreadable
    let arr1 = ['c', 'd'];
    ['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
    arr1[Symbol.isConcatSpreadable] // undefined
    
    let arr2 = ['c', 'd'];
    arr2[Symbol.isConcatSpreadable] = false;
    ['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']
    
    ---
    
    let obj = {length: 2, 0: 'c', 1: 'd'};
    ['a', 'b'].concat(obj, 'e') // ['a', 'b', obj, 'e']
    
    obj[Symbol.isConcatSpreadable] = true;
    ['a', 'b'].concat(obj, 'e') // ['a', 'b', 'c', 'd', 'e']
    
    ---
    
    class A1 extends Array {
      constructor(args) {
        super(args);
        this[Symbol.isConcatSpreadable] = true;
      }
    }
    class A2 extends Array {
      constructor(args) {
        super(args);
      }
      get [Symbol.isConcatSpreadable] () {
        return false;
      }
    }
    let a1 = new A1();
    a1[0] = 3;
    a1[1] = 4;
    let a2 = new A2();
    a2[0] = 5;
    a2[1] = 6;
    [1, 2].concat(a1).concat(a2)
    // [1, 2, 3, 4, [5, 6]]
    
    // Symbol.match
    String.prototype.match(regexp)
    // 等同于
    regexp[Symbol.match](this)
    
    class MyMatcher {
      [Symbol.match](string) {
        return 'hello world'.indexOf(string);
      }
    }
    
    'e'.match(new MyMatcher()) // 1
    

    Proxy & Reflect

    // var proxy = new Proxy(target, handler);
    // Reflect.get(target, name, receiver)
    // Reflect.set(target, name, value, receiver)
    
    var obj = new Proxy({}, {
      get: function (target, propKey, receiver) {
        console.log(`getting ${propKey}!`);
        return Reflect.get(target, propKey, receiver);
      },
      set: function (target, propKey, value, receiver) {
        console.log(`setting ${propKey}!`);
        return Reflect.set(target, propKey, value, receiver);
      }
    });
    
    obj.count = 1
    //  setting count!
    ++obj.count
    //  getting count!
    //  setting count!
    //  2
    
    Reflect.apply(target, thisArg, args)
    Reflect.construct(target, args)
    Reflect.get(target, name, receiver)
    Reflect.set(target, name, value, receiver)
    Reflect.defineProperty(target, name, desc)
    Reflect.deleteProperty(target, name)
    Reflect.has(target, name)
    Reflect.ownKeys(target)
    Reflect.isExtensible(target)
    Reflect.preventExtensions(target)
    Reflect.getOwnPropertyDescriptor(target, name)
    Reflect.getPrototypeOf(target)
    Reflect.setPrototypeOf(target, prototype)
    

    Promise

    1. 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
    2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果

    缺点:Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    
    // 基本用法
    const promise = new Promise(function(resolve, reject) {
      if (true){
        resolve(value);
      } else {
        reject(error);
      }
    });
    
    // then
    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    });
    
    // catch、finally
    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···});
    
    // Promise.all() 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
    //(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
    //(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
    const p = Promise.all([p1, p2, p3]);
    
    // Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
    // 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
    const p = Promise.race([p1, p2, p3]);
    
    const p = Promise.race([
      fetch('/resource-that-may-take-a-while'),
      new Promise(function (resolve, reject) {
        setTimeout(() => reject(new Error('request timeout')), 5000)
      })
    ]);
    
    p
    .then(console.log)
    .catch(console.error);
    
    
    // Promise.allSettled()方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。
    
    const resolved = Promise.resolve(42);
    const rejected = Promise.reject(-1);
    
    const allSettledPromise = Promise.allSettled([resolved, rejected]);
    
    allSettledPromise.then(function (results) {
      console.log(results);
    });
    
    // Promise.any()方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
    
    var resolved = Promise.resolve(42);
    var rejected = Promise.reject(-1);
    var alsoRejected = Promise.reject(Infinity);
    
    Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
      console.log(result); // 42
    });
    
    Promise.any([rejected, alsoRejected]).catch(function (results) {
      console.log(results); // [-1, Infinity]
    });
    
    
    // Promise.resolve() 
    // Promise.reject() 
    

    Iterator

    // 遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
    
    // Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
    
    var it = makeIterator(['a', 'b']);
    
    it.next() // { value: "a", done: false }
    it.next() // { value: "b", done: false }
    it.next() // { value: undefined, done: true }
    
    function makeIterator(array) {
      var nextIndex = 0;
      return {
        next: function() {
          return nextIndex < array.length ?
            {value: array[nextIndex++], done: false} :
            {value: undefined, done: true};
        }
      };
    }
    
    // 原生具备 Iterator 接口的数据结构如下。
    // Array
    // Map
    // Set
    // String
    // TypedArray
    // 函数的 arguments 对象
    // NodeList 对象
    
    //一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法。
    

    Generator

    function* helloWorldGenerator() {
      yield 'hello';
      yield 'world';
      return 'ending';
    }
    
    var hw = helloWorldGenerator();
    
    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 与 Iterator 接口的关系。任意一个对象的Symbol.iterator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。
    
    //由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的Symbol.iterator属性,从而使得该对象具有 Iterator 接口。
    
    var myIterable = {};
    myIterable[Symbol.iterator] = function* () {
      yield 1;
      yield 2;
      yield 3;
    };
    
    [...myIterable] // [1, 2, 3]
    
    
    // next 方法的参数,yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
    
    function* foo(x) {
      var y = 2 * (yield (x + 1));
      var z = yield (y / 3);
      return (x + y + z);
    }
    
    var a = foo(5);
    a.next() // Object{value:6, done:false}
    a.next() // Object{value:NaN, done:false}
    a.next() // Object{value:NaN, done:true}
    
    var b = foo(5);
    b.next() // { value:6, done:false }
    b.next(12) // { value:8, done:false }
    b.next(13) // { value:42, done:true }
    
    // for...of 循环
    
    function* foo() {
      yield 1;
      yield 2;
      yield 3;
      yield 4;
      yield 5;
      return 6;
    }
    
    for (let v of foo()) {
      console.log(v);
    }
    
    // Generator.prototype.throw() Generator函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获。
    
    var g = function* () {
      try {
        yield;
      } catch (e) {
        console.log('内部捕获', e);
      }
    };
    
    var i = g();
    i.next();
    
    try {
      i.throw('a');
      i.throw('b');
    } catch (e) {
      console.log('外部捕获', e);
    }
    
    // 上面代码中,遍历器对象i连续抛出两个错误。第一个错误被 Generator 函数体内的catch语句捕获。i第二次抛出错误,由于 Generator 函数内部的catch语句已经执行过了,不会再捕捉到这个错误了,所以这个错误就被抛出了 Generator 函数体,被函数体外的catch语句捕获。
    
    // Generator.prototype.return()
    
    function* gen() {
      yield 1;
      yield 2;
      yield 3;
    }
    
    var g = gen();
    
    g.next()        // { value: 1, done: false }
    g.return('foo') // { value: "foo", done: true }
    g.next()  
    

    async、await

    // async 函数是什么?一句话,它就是 Generator 函数的语法糖。
    
    var fs = {
      readFile: function(fileName, cb) {
        setTimeout(() => {
          cb && cb(false, fileName + " content");
        }, 1000);
      }
    };
    
    var readFile = function(fileName) {
      return new Promise(function(resolve, reject) {
        fs.readFile(fileName, function(error, data) {
          if (error) return reject(error);
          resolve(data);
        });
      });
    };
    
    var gen = function* () {
      var f1 = yield readFile("/etc/fstab");
      var f2 = yield readFile("/etc/shells");
    };
    
    const asyncReadFile = async function() {
      const f1 = await readFile("/etc/fstab");
      console.log(f1);
      const f2 = await readFile("/etc/shells");
      console.log(f2);
    };
    
    var g = gen();
    g.next().value.then((res) => {
      console.log(res);
    });
    g.next().value.then((res) => {
      console.log(res);
    });
    
    asyncReadFile().then((res) => {
      console.log(res);
    });
    
    //async函数对 Generator 函数的改进,体现在以下四点。
    //(1)内置执行器。
    //(2)更好的语义。
    //(3)更广的适用性。
    //(4)返回值是 Promise。
    
    //async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
    
    //返回 Promise 对象,async函数内部return语句返回的值,会成为then方法回调函数的参数。
    async function f() {
      return 'hello world';
    }
    
    f().then(v => console.log(v))
    // "hello world"
    
    //async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
    async function f() {
      throw new Error('出错了');
    }
    
    f().then(
      v => console.log(v),
      e => console.log(e)
    )
    // Error: 出错了
    
    //async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
    

    Calss

    // Mixin 模式的实现
    
    //Mixin 指的是多个对象合成一个新的对象,新对象具有各个组成成员的接口。它的最简单实现如下。
    
    const a = {
      a: 'a'
    };
    const b = {
      b: 'b'
    };
    const c = {...a, ...b}; // {a: 'a', b: 'b'}
    上面代码中,c对象是a对象和b对象的合成,具有两者的接口。
    
    下面是一个更完备的实现,将多个类的接口“混入”(mix in)另一个类。
    
    function mix(...mixins) {
      class Mix {
        constructor() {
          for (let mixin of mixins) {
            copyProperties(this, new mixin()); // 拷贝实例属性
          }
        }
      }
    
      for (let mixin of mixins) {
        copyProperties(Mix, mixin); // 拷贝静态属性
        copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性
      }
    
      return Mix;
    }
    
    function copyProperties(target, source) {
      for (let key of Reflect.ownKeys(source)) {
        if ( key !== 'constructor'
          && key !== 'prototype'
          && key !== 'name'
        ) {
          let desc = Object.getOwnPropertyDescriptor(source, key);
          Object.defineProperty(target, key, desc);
        }
      }
    }
    
    //上面代码的mix函数,可以将多个对象合成为一个类。使用的时候,只要继承这个类即可。
    
    class DistributedEdit extends mix(Loggable, Serializable) {
      // ...
    }
    
    

    相关文章

      网友评论

          本文标题:ECMAScript 6 新增内容

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