zoukankan      html  css  js  c++  java
  • ECMA 2022 (es13) 新特性

    本文主要整理了截至到 2021年10月12日 为止的且处于 Stage 3->Stage 4 阶段的ECMA提案。

    主要包括:

    • Class Fields
    • RegExp Match Indices
    • Top-Level await
    • Ergonomic brand checks for Private Fields
    • .at
    • Object.hasOwn()
    • Class Static Block

    Class Fields

    class 相关的提案一共有三个,目前都处于 Stage 3 阶段。

    Private instance methods and accessors

    示例:

    /**** es2015 ****/
    class Counter extends HTMLElement {
      get x() { return this.xValue; }
      set x(value) {
        this.xValue = value;
        window.requestAnimationFrame(this.render.bind(this));
      }
    
      clicked() {
        this.x++;
      }
    
      constructor() {
        super();
        this.onclick = this.clicked.bind(this);
        this.xValue = 0;
      }
    
      connectedCallback() { this.render(); }
    
      render() {
        this.textContent = this.x.toString();
      }
    }
    window.customElements.define('num-counter', Counter);
    /**** now(exNext) ****/
    class Counter extends HTMLElement {
      xValue = 0; // 声明共有属性
    
      get x() { return this.xValue; }
      set x(value) {
        this.xValue = value;
        window.requestAnimationFrame(this.render.bind(this));
      }
    
      clicked() {
        this.x++;
        window.requestAnimationFrame(this.render.bind(this));
      }
    
      constructor() {
        super();
        this.onclick = this.clicked.bind(this);
      }
    
      connectedCallback() { this.render(); }
    
      render() {
        this.textContent = this.x.toString();
      }
    }
    window.customElements.define('num-counter', Counter);
    

    Class Public Instance Fields & Private Instance Fields

    示例:

    // es2015
    class Counter extends HTMLElement {
      clicked() {
        this.x++;
        window.requestAnimationFrame(this.render.bind(this));
      }
    
      constructor() {
        super();
        this.onclick = this.clicked.bind(this);
        this.x = 0;
      }
    
      connectedCallback() { this.render(); }
    
      render() {
        this.textContent = this.x.toString();
      }
    }
    window.customElements.define('num-counter', Counter);
    // now 
    class Counter extends HTMLElement {
      x = 0;
    
      clicked() {
        this.x++;
        window.requestAnimationFrame(this.render.bind(this));
      }
    
      constructor() {
        super();
        this.onclick = this.clicked.bind(this);
      }
    
      connectedCallback() { this.render(); }
    
      render() {
        this.textContent = this.x.toString();
      }
    }
    window.customElements.define('num-counter', Counter);
    // 结合私有字段
    class Counter extends HTMLElement {
      #x = 0;
    
      clicked() {
        this.#x++;
        window.requestAnimationFrame(this.render.bind(this));
      }
    
      constructor() {
        super();
        this.onclick = this.clicked.bind(this);
      }
    
      connectedCallback() { this.render(); }
    
      render() {
        this.textContent = this.#x.toString();
      }
    }
    window.customElements.define('num-counter', Counter);
    

    Static class fields and private static methods

    class Test {
    
        static instance = new Test(0);// 静态共有变量
    
        static #value=123; // 静态私有变量
        // 静态私有方法
        static #print(){
            return this.#value;
        }
    }
    

    RegExp Match Indices

    正则的匹配模式之前只有i g m,现在增加 d,目前处于 Stage 4 阶段。

    示例:

    const re1 = /a+(?<Z>z)?/d;
    
    // indices are relative to start of the input string:
    const s1 = "xaaaz";
    const m1 = re1.exec(s1);
    m1.indices[0][0] === 1;
    m1.indices[0][1] === 5;
    s1.slice(...m1.indices[0]) === "aaaz";
    
    m1.indices[1][0] === 4;
    m1.indices[1][1] === 5;
    s1.slice(...m1.indices[1]) === "z";
    
    m1.indices.groups["Z"][0] === 4;
    m1.indices.groups["Z"][1] === 5;
    s1.slice(...m1.indices.groups["Z"]) === "z";
    
    // capture groups that are not matched return `undefined`:
    const m2 = re1.exec("xaaay");
    m2.indices[1] === undefined;
    m2.indices.groups["Z"] === undefined;
    

    使用 d 后给 上面代码中的 m1 增加 indices 属性。

    Top-Level await

    之前只能 async await, 现在则可以直接使用 await ,目前处于 Stage 4 阶段。

    示例:

    /*** before ***/
    // awaiting.mjs
    import { process } from "./some-module.mjs";
    export default (async () => {
      const dynamic = await import(computedModuleSpecifier);
      const data = await fetch(url);
      const output = process(dynamic.default, data);
      return { output };
    })();
    // usage.mjs
    import promise from "./awaiting.mjs";
    
    export default promise.then(({output}) => {
      function outputPlusValue(value) { return output + value }
    
      console.log(outputPlusValue(100));
      setTimeout(() => console.log(outputPlusValue(100), 1000);
    
      return { outputPlusValue };
    });
    
    /*** now ***/
    // awaiting.mjs
    import { process } from "./some-module.mjs";
    const dynamic = import(computedModuleSpecifier);
    const data = fetch(url);
    export const output = process((await dynamic).default, await data);
    // usage.mjs
    import { output } from "./awaiting.mjs";
    export function outputPlusValue(value) { return output + value }
    
    console.log(outputPlusValue(100));
    setTimeout(() => console.log(outputPlusValue(100), 1000);
    

    Ergonomic brand checks for Private Fields

    这个提案的作用是检测一个对象中是否存在私有变量,目前处于 Stage 4 阶段。

    示例:

    class C {
      #brand;
    
      #method() {}
    
      get #getter() {}
    
      static isC(obj) {
        return #brand in obj && #method in obj && #getter in obj;
      }
    }
    

    .at

    在所有基本可索引类中添加 .at() 方法,目前处于 Stage 3 阶段。

    很多时候,类似于 Python 中的数组负值索引可以非常实用。比如在 Python 中我们可以通过 arr[-1] 来访问数组中的最后一个元素,而不用通过目前 JavaScript 中的方式来访问 arr[arr.length-1]。这里的负数是作为从起始元素(即arr[0])开始的反向索引。

    但是现在 JavaScript 中的问题是,[] 这个语法不仅仅只是在数组中使用(当然在 Python 中也不是),而在数组中也不仅仅只可以作为索引使用。像arr[1]一样通过索引引用一个值,事实上引用的是这个对象的 "1" 这个属性。所以 arr[-1] 已经完全可以在现在的 JavaScript 引擎中使用,只是它可能不是代表的我们想要表达的意思而已:它引用的是目标对象的 "-1" 这个属性,而不是一个反向索引。

    这个提案提供了一个通用的方案,我们可以通过任意可索引的类型(Array,String,和 TypedArray)上的 .at 方法,来访问任意一个反向索引、或者是正向索引的元素。

    示例:

    const arr = [1,2];
    arr.at(-1); // 2
    arr.at(-2); // 1
    

    Object.hasOwn()

    采用一种使更易于访问的方法替代 Object.prototype.hasOwnProperty(),目前处于 Stage 4 阶段。

    其实现在我们就可以通过 Object.prototype.hasOwnProperty 来使用提案所包含的特性。但是直接通过对象自身的 hasOwnProperty 来使用 obj.hasOwnProperty('foo') 是不安全的,因为这个 obj 可能覆盖了 hasOwnProperty 的定义,MDN 上也对这种使用方式进行了警告。

    JavaScript 并没有保护 hasOwnProperty 这个属性名,因此,当某个对象可能自有一个占用该属性名的属性时,就需要使用外部的 hasOwnProperty 获得正确的结果...

    示例:

    let hasOwnProperty = Object.prototype.hasOwnProperty
    
    if (hasOwnProperty.call(object, "foo")) {
      console.log("has property foo")
    }
    
    // 此提案将该代码简化为:
    
    if (Object.hasOwn(object, "foo")) {
      console.log("has property foo")
    }
    

    Class Static Block

    类块提供了在类定义评估期间执行额外静态初始化的机制,目前处于 Stage 4 阶段

    自从有了 Class Private Fields,对于类的语法是不断地有新的实践与需求。这个提案提议的 Class Static 初始化块会在类被执行、初始化时被执行。

    提案中定义的初始化代码块可以获得 class 内的作用域,如同 class 的方法一样,也意味着可以访问类的 #字段

    let getX;
    
    export class C {
      #x
      constructor(x) {
        this.#x = { data: x };
      }
    
      static {
        // getX has privileged access to #x
        getX = (obj) => obj.#x;
      }
    }
    
    export function readXData(obj) {
      return getX(obj).data;
    }
    

    参考资料

  • 相关阅读:
    test
    莫烦Python
    资源汇总
    AutoHotkey学习资源
    神器AutoHotkey学习(官方文档翻译)
    linux内核编译时bad register name `%dil'错误
    Linux内核修炼之道-->原作者博客链接--oschina备份
    vim笔记--oschina备份
    vim相关资源--oschina备份
    Windows下装Gvim时可能发生的错误--oschina备份
  • 原文地址:https://www.cnblogs.com/guojikun/p/15399917.html
Copyright © 2011-2022 走看看