中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

ECMAScript新特性有哪些

發布時間:2022-07-05 11:46:20 來源:億速云 閱讀:175 作者:iii 欄目:開發技術

本篇內容介紹了“ECMAScript新特性有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

1. Top-level Await

在ES2017中,引入了 async 函數和 await 關鍵字,以簡化 Promise 的使用,但是 await 關鍵字只能在 async 函數內部使用。嘗試在異步函數之外使用 await 就會報錯:SyntaxError - SyntaxError: await is only valid in async function

頂層 await 允許我們在 async 函數外面使用 await 關鍵字。它允許模塊充當大型異步函數,通過頂層 await,這些 ECMAScript 模塊可以等待資源加載。這樣其他導入這些模塊的模塊在執行代碼之前要等待資源加載完再去執行。

由于 await 僅在 async 函數中可用,因此模塊可以通過將代碼包裝在 async 函數中來在代碼中包含 await

  // a.js
  import fetch  from "node-fetch";
  let users;

  export const fetchUsers = async () => {
    const resp = await fetch('https://jsonplaceholder.typicode.com/users');
    users =  resp.json();
  }
  fetchUsers();

  export { users };

  // usingAwait.js
  import {users} from './a.js';
  console.log('users: ', users);
  console.log('usingAwait module');

我們還可以立即調用頂層async函數(IIAFE):

import fetch  from "node-fetch";
  (async () => {
    const resp = await fetch('https://jsonplaceholder.typicode.com/users');
    users = resp.json();
  })();
  export { users };

這樣會有一個缺點,直接導入的 usersundefined,需要在異步執行完成之后才能訪問它:

// usingAwait.js
import {users} from './a.js';

console.log('users:', users); // undefined

setTimeout(() => {
  console.log('users:', users);
}, 100);

console.log('usingAwait module');

當然,這種方法并不安全,因為如果異步函數執行花費的時間超過100毫秒, 它就不會起作用了,users 仍然是 undefined

另一個方法是導出一個 promise,讓導入模塊知道數據已經準備好了:

//a.js
import fetch  from "node-fetch";
export default (async () => {
  const resp = await fetch('https://jsonplaceholder.typicode.com/users');
  users = resp.json();
})();
export { users };

//usingAwait.js
import promise, {users} from './a.js';
promise.then(() => { 
  console.log('usingAwait module');
  setTimeout(() => console.log('users:', users), 100); 
});

雖然這種方法似乎是給出了預期的結果,但是有一定的局限性:導入模塊必須了解這種模式才能正確使用它

而頂層await就可以解決這些問題:

  // a.js
  const resp = await fetch('https://jsonplaceholder.typicode.com/users');
  const users = resp.json();
  export { users};

  // usingAwait.js
  import {users} from './a.mjs';

  console.log(users);
  console.log('usingAwait module');

頂級 await 在以下場景中將非常有用:

  • 動態加載模塊:

 const strings = await import(`/i18n/${navigator.language}`);
  • 資源初始化:

const connection = await dbConnector();
  • 依賴回退:

let translations;
try {
  translations = await import('https://app.fr.json');
} catch {
  translations = await import('https://fallback.en.json');
}

該特性的瀏覽器支持如下:

ECMAScript新特性有哪些

2. Object.hasOwn()

在ES2022之前,可以使用 Object.prototype.hasOwnProperty() 來檢查一個屬性是否屬于對象。

Object.hasOwn 特性是一種更簡潔、更可靠的檢查屬性是否直接設置在對象上的方法:

const example = {
  property: '123'
};

console.log(Object.prototype.hasOwnProperty.call(example, 'property'));
console.log(Object.hasOwn(example, 'property'));

該特性的瀏覽器支持如下:

ECMAScript新特性有哪些

3. at()

at() 是一個數組方法,用于通過給定索引來獲取數組元素。當給定索引為正時,這種新方法與使用括號表示法訪問具有相同的行為。當給出負整數索引時,就會從數組的最后一項開始檢索:

const array = [0,1,2,3,4,5];

console.log(array[array.length-1]);  // 5
console.log(array.at(-1));  // 5

console.log(array[array.lenght-2]);  // 4
console.log(array.at(-2));  // 4

除了數組,字符串也可以使用at()方法進行索引:

const str = "hello world";

console.log(str[str.length - 1]);  // d
console.log(str.at(-1));  // d

4. error.cause

在 ECMAScript 2022 規范中,new Error() 中可以指定導致它的原因:

function readFiles(filePaths) {
  return filePaths.map(
    (filePath) => {
      try {
        // ···
      } catch (error) {
        throw new Error(
          `While processing ${filePath}`,
          {cause: error}
        );
      }
    });
}

5. 正則表達式匹配索引

該特性允許我們利用 d 字符來表示我們想要匹配字符串的開始和結束索引。以前,只能在字符串匹配操作期間獲得一個包含提取的字符串和索引信息的數組。在某些情況下,這是不夠的。因此,在這個規范中,如果設置標志 /d,將額外獲得一個帶有開始和結束索引的數組。

const matchObj = /(a+)(b+)/d.exec('aaaabb');

console.log(matchObj[1]) // 'aaaa'
console.log(matchObj[2]) // 'bb'

由于 /d 標識的存在,matchObj還有一個屬性.indices,它用來記錄捕獲的每個編號組:

console.log(matchObj.indices[1])  // [0, 4]
console.log(matchObj.indices[2])  // [4, 6]

我們還可以使用命名組:

const matchObj = /(?<as>a+)(?<bs>b+)/d.exec('aaaabb');

console.log(matchObj.groups.as);  // 'aaaa'
console.log(matchObj.groups.bs);  // 'bb'

這里給兩個字符匹配分別命名為asbs,然后就可以通過groups來獲取到這兩個命名分別匹配到的字符串。

它們的索引存儲在 matchObj.indices.groups 中:

console.log(matchObj.indices.groups.as);  // [0, 4]
console.log(matchObj.indices.groups.bs);  // [4, 6]

匹配索引的一個重要用途就是指向語法錯誤所在位置的解析器。下面的代碼解決了一個相關問題:它指向引用內容的開始和結束位置。

const reQuoted = /“([^”]+)”/dgu;
function pointToQuotedText(str) {
  const startIndices = new Set();
  const endIndices = new Set();
  for (const match of str.matchAll(reQuoted)) {
    const [start, end] = match.indices[1];
    startIndices.add(start);
    endIndices.add(end);
  }
  let result = '';
  for (let index=0; index < str.length; index++) {
    if (startIndices.has(index)) {
      result += '[';
    } else if (endIndices.has(index+1)) {
      result += ']';
    } else {
      result += ' ';
    }
  }
  return result;
}

console.log(pointToQuotedText('They said “hello” and “goodbye”.'));
// '           [   ]       [     ]  '

6. 類的實例成員

(1)公共實例字段

公共類字段允許我們使用賦值運算符 (=) 將實例屬性添加到類定義中。下面是一個計數器的例子:

import React, { Component } from "react";

export class Incrementor extends Component {
  constructor() {
    super();
    this.state = {
      count: 0,
    };
    this.increment = this.increment.bind(this);
  }

  increment() {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <button onClick={this.increment}>Increment: {this.state.count}</button>
    );
  }
}

在這個例子中,在構造函數中定義了實例字段和綁定方法,通過新的類語法,可以使代碼更加直觀。新的公共類字段語法允許我們直接將實例屬性作為屬性添加到類上,而無需使用構造函數方法。這樣就簡化了類的定義,使代碼更加簡潔、可讀:

import React from "react";

export class Incrementor extends React.Component {
  state = { count: 0 };

  increment = () => this.setState({ count: this.state.count + 1 });

  render = () => (
    <button onClick={this.increment}>Increment: {this.state.count}</button>
  );
}

有些小伙伴可能就疑問了,這個功能很早就可以使用了呀。但是它現在還不是標準的 ECMAScript,默認是不開啟的,如果使用 create-react-app 創建 React 項目,那么它默認是啟用的,否則我們必須使用正確的babel插件才能正常使用(@babel/preset-env)。

下面來看看關于公共實例字段的注意事項:

  • 公共實例字段存在于每個創建的類實例上。它們要么是在Object.defineProperty()中添加,要么是在基類中的構造時添加(構造函數主體執行之前執行),要么在子類的super()返回之后添加:

class Incrementor {
  count = 0
}

const instance = new Incrementor();
console.log(instance.count); // 0
  • 未初始化的字段會自動設置為 undefined

class Incrementor {
  count
}

const instance = new Incrementor();
console.assert(instance.hasOwnProperty('count'));
console.log(instance.count);  // undefined
  • 可以進行字段的計算:

const PREFIX = 'main';

class Incrementor {
  [`${PREFIX}Count`] = 0
}

const instance = new Incrementor();
console.log(instance.mainCount);   // 0

(2)私有實例字段、方法和訪問器

默認情況下,ES6 中所有屬性都是公共的,可以在類外檢查或修改。下面來看一個例子:

class TimeTracker {
  name = 'zhangsan';
  project = 'blog';
  hours = 0;

  set addHours(hour) {
    this.hours += hour;
  }

  get timeSheet() {
    return `${this.name} works ${this.hours || 'nothing'} hours on ${this.project}`;
  }
}

let person = new TimeTracker();
person.addHours = 2; // 標準 setter
person.hours = 4;    // 繞過 setter 進行設置
person.timeSheet;

可以看到,在類中沒有任何措施可以防止在不調用 setter 的情況下更改屬性。

而私有類字段將使用哈希#前綴定義,從上面的示例中,可以修改它以包含私有類字段,以防止在類方法之外更改屬性:

class TimeTracker {
  name = 'zhangsan';
  project = 'blog';
  #hours = 0;  // 私有類字段

  set addHours(hour) {
    this.#hours += hour;
  }

  get timeSheet() {
    return `${this.name} works ${this.#hours || 'nothing'} hours on ${this.project}`;
  }
}

let person = new TimeTracker();
person.addHours = 4; // 標準 setter
person.timeSheet     // zhangsan works 4 hours on blog

當嘗試在 setter 方法之外修改私有類字段時,就會報錯:

person.hours = 4 // Error Private field '#hours' must be declared in an enclosing class

還可以將方法或 getter/setter 設為私有,只需要給這些方法名稱前面加#即可:

class TimeTracker {
  name = 'zhangsan';
  project = 'blog';
  #hours = 0;   // 私有類字段

  set #addHours(hour) {
    this.#hours += hour;
  }

  get #timeSheet() {
    return `${this.name} works ${this.#hours || 'nothing'} hours on ${this.project}`;
  }

  constructor(hours) {
    this.#addHours = hours;
    console.log(this.#timeSheet);
  }
}

let person = new TimeTracker(4); // zhangsan works 4 hours on blog

由于嘗試訪問對象上不存在的私有字段會發生異常,因此需要能夠檢查對象是否具有給定的私有字段。可以使用 in 運算符來檢查對象上是否有私有字段:

class Example {
  #field

  static isExampleInstance(object) {
    return #field in object;
  }
}

(3)靜態公共字段

在ES6中,不能在類的每個實例中訪問靜態字段或方法,只能在原型中訪問。ES 2022 提供了一種在 JavaScript 中使用 static 關鍵字聲明靜態類字段的方法。下面來看一個例子:

class Shape {
  static color = 'blue';

  static getColor() {
    return this.color;
  }

  getMessage() {
    return `color:${this.color}` ;
  }
}

可以從類本身訪問靜態字段和方法:

  console.log(Shape.color); // blue
  console.log(Shape.getColor()); // blue
  console.log('color' in Shape); // true
  console.log('getColor' in Shape); // true
  console.log('getMessage' in Shape); // false

實例不能訪問靜態字段和方法:

  const shapeInstance = new Shape();
  console.log(shapeInstance.color); // undefined
  console.log(shapeInstance.getColor); // undefined
  console.log(shapeInstance.getMessage());// color:undefined

靜態字段只能通過靜態方法訪問:

console.log(Shape.getColor()); // blue
console.log(Shape.getMessage()); //TypeError: Shape.getMessage is not a function

這里的 Shape.getMessage() 就報錯了,因為 getMessage 不是一個靜態函數,所以它不能通過類名 Shape 訪問。可以通過以下方式來解決這個問題:

getMessage() {
  return `color:${Shape.color}` ;
}

靜態字段和方法是從父類繼承的:

class Rectangle extends Shape { }

console.log(Rectangle.color); // blue
console.log(Rectangle.getColor()); // blue
console.log('color' in Rectangle); // true
console.log('getColor' in Rectangle); // true
console.log('getMessage' in Rectangle); // false

(4)靜態私有字段和方法

與私有實例字段和方法一樣,靜態私有字段和方法也使用哈希 (#) 前綴來定義:

class Shape {
  static #color = 'blue';

  static #getColor() {
    return this.#color;
  }

  getMessage() {
    return `color:${Shape.#getColor()}` ;
  }
}
const shapeInstance = new Shape();
shapeInstance.getMessage(); // color:blue

私有靜態字段有一個限制:只有定義私有靜態字段的類才能訪問該字段。這可能在使用 this 時導致出乎意料的情況:

class Shape {
  static #color = 'blue';
static #getColor() {
  return this.#color;
}
static getMessage() {
  return `color:${this.#color}` ;
}
getMessageNonStatic() {
  return `color:${this.#getColor()}` ;
}
}

class Rectangle extends Shape {}

console.log(Rectangle.getMessage()); // Uncaught TypeError: Cannot read private member #color from an object whose class did not declare it
const rectangle = new Rectangle();
console.log(rectangle.getMessageNonStatic()); // TypeError: Cannot read private member #getColor from an object whose class did not declare it

在這個例子中,this 指向的是 Rectangle 類,它無權訪問私有字段 #color。當我們嘗試調用 Rectangle.getMessage() 時,它無法讀取 #color 并拋出了 TypeError。可以這樣來進行修改:

class Shape {
  static #color = 'blue';
  static #getColor() {
    return this.#color;
  }
  static getMessage() {
    return `${Shape.#color}`;
  }
  getMessageNonStatic() {
    return `color:${Shape.#getColor()} color`;
  }
}

class Rectangle extends Shape {}
console.log(Rectangle.getMessage()); // color:blue
const rectangle = new Rectangle();
console.log(rectangle.getMessageNonStatic()); // color:blue

(5)類靜態初始化塊

靜態私有和公共字段只能讓我們在類定義期間執行靜態成員的每個字段初始化。如果我們需要在初始化期間像 try…catch 一樣進行異常處理,就不得不在類之外編寫此邏輯。該規范就提供了一種在類聲明/定義期間評估靜態初始化代碼塊的優雅方法,可以訪問類的私有字段。

先來看一個例子:

class Person {
    static GENDER = "Male"
    static TOTAL_EMPLOYED;
    static TOTAL_UNEMPLOYED;

    try {
        // ...
    } catch {
        // ...
    }
}

上面的代碼就會引發錯誤,可以使用類靜態塊來重構它,只需將try...catch包裹在 static 中即可:

class Person {
    static GENDER = "Male"
    static TOTAL_EMPLOYED;
    static TOTAL_UNEMPLOYED;
    
  static {
  	try {
        // ...
    } catch {
        // ...
    }
  }
}

此外,類靜態塊提供對詞法范圍的私有字段和方法的特權訪問。這里需要在具有實例私有字段的類和同一范圍內的函數之間共享信息的情況下很有用。

let getData;

class Person {
  #x
  
  constructor(x) {
    this.#x = { data: x };
  }

  static {
    getData = (obj) => obj.#x;
  }
}

function readPrivateData(obj) {
  return getData(obj).data;
}

const john = new Person([2,4,6,8]);

readPrivateData(john); // [2,4,6,8]

這里,Person 類與 readPrivateData 函數共享了私有實例屬性。

“ECMAScript新特性有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

南岸区| 孟村| 新干县| 布尔津县| 天峨县| 任丘市| 会理县| 麻城市| 邹城市| 德庆县| 盐津县| 古田县| 沙湾县| 沾化县| 普格县| 涞水县| 吉林省| 信丰县| 靖远县| 望都县| 台南市| 彭水| 府谷县| 鞍山市| 伊川县| 大足县| 黎平县| 南投市| 静乐县| 普洱| 元朗区| 梁平县| 新乡县| 壶关县| 织金县| 安阳市| 曲麻莱县| 黑水县| 新民市| 望谟县| 兰坪|