這些 JS 的新語法有點東西啊

TC39 的提案筆者一直有關注,攢了一些有趣的今天來聊聊。git

PS:提案總共五個階段,只有到階段 4 纔會被歸入到發佈規範中,其它的只是有概率會被歸入。github

.at()

這是個挺不錯的新語法。其餘有些語言是能夠用 arr[-1] 來獲取數組末尾的元素,可是對於 JS 來講這是實現不了的事情。由於 [key] 對於對象來講就是在獲取 key 對應的值。數組也是對象,對於數組使用 arr[-1] 就是在獲取 key-1 的值。web

因爲以上緣由,咱們想獲取末尾元素就得這樣寫 arr[arr.length - 1],之後有了 at 這個方法,咱們就能夠經過 arr.at(-1) 來拿末尾的元素了,另外一樣適用類數組、字符串。編程

// Polyfill
function at(n) {
    // ToInteger() abstract op
    n = Math.trunc(n) || 0;
    // Allow negative indexing from the end
    if(n < 0) n += this.length;
    // OOB access is guaranteed to return undefined
    if(n < 0 || n >= this.length) return undefined;
    // Otherwise, this is just normal property access
    return this[n];
}
複製代碼

頂層 await

await 都得用 async 函數包裹你們確定都知道,這個限制致使咱們不能在全局做用域下直接使用 await,必須得包裝一下。api

有了這個提案之後,你們就能夠直接在頂層寫 await 了,算是一個便利性的提案。數組

目前該提案已經進入階段 4,板上釘釘會發布。另外其實 Chrome 近期的更新已經支持了該功能。性能優化

image-20210620162451146

Error Cause

這個語法主要幫助咱們便捷地傳遞 Error。一旦可能出錯的地方一多,咱們實際就不清楚錯誤究竟是哪裏產生的。若是但願外部清楚的知道上下文信息的話,咱們須要封裝如下 error。markdown

async function getSolution() {
  const rawResource = await fetch('//domain/resource-a')
    .catch(err => {
      // How to wrap the error properly?
      // 1. throw new Error('Download raw resource failed: ' + err.message);
      // 2. const wrapErr = new Error('Download raw resource failed');
      // wrapErr.cause = err;
      // throw wrapErr;
      // 3. class CustomError extends Error {
      // constructor(msg, cause) {
      // super(msg);
      // this.cause = cause;
      // }
      // }
      // throw new CustomError('Download raw resource failed', err);
    })
  const jobResult = doComputationalHeavyJob(rawResource);
  await fetch('//domain/upload', { method: 'POST', body: jobResult });
}

await doJob(); // => TypeError: Failed to fetch
複製代碼

那麼有了這個語法之後,咱們能夠這樣來簡化代碼:數據結構

async function doJob() {
  const rawResource = await fetch('//domain/resource-a')
    .catch(err => {
      throw new Error('Download raw resource failed', { cause: err });
    });
  const jobResult = doComputationalHeavyJob(rawResource);
  await fetch('//domain/upload', { method: 'POST', body: jobResult })
    .catch(err => {
      throw new Error('Upload job result failed', { cause: err });
    });
}

try {
  await doJob();
} catch (e) {
  console.log(e);
  console.log('Caused by', e.cause);
}
// Error: Upload job result failed
// Caused by TypeError: Failed to fetch
複製代碼

管道運算符

這個語法的 Star 特別多,有 5k 多個,側面也能說明是個受歡迎的語法,可是距離發佈應該還有很久,畢竟這個提案三四年前就有了,目前還只到階段 1。frontend

這個語法其實在其餘函數式編程語言上很常見,主要是爲了函數調用方便:

let result = exclaim(capitalize(doubleSay("hello")));
result //=> "Hello, hello!"

let result = "hello"
  |> doubleSay
  |> capitalize
  |> exclaim;

result //=> "Hello, hello!"
複製代碼

這只是對於單個參數的用法,其它的用法有興趣的讀者能夠自行閱讀提案,其中涉及到了特別多的內容,這大概也是致使推動階段慢的緣由吧。

新的數據結構:Records & Tuples

這個數據結構筆者以爲發佈之後會特別有用,總共新增了兩種數據結構,咱們能夠經過 # 來聲明:

  1. #{ x: 1, y: 2 }
  2. #[1, 2, 3, 4]

這種數據結構是不可變的,相似 React 中爲了作性能優化會引入的 immer 或者 immutable.js,其中的值只接受基本類型或者同是不可變的數據類型。

const proposal = #{
  id: 1234,
  title: "Record & Tuple proposal",
  contents: `...`,
  // tuples are primitive types so you can put them in records:
  keywords: #["ecma", "tc39", "proposal", "record", "tuple"],
};

// Accessing keys like you would with objects!
console.log(proposal.title); // Record & Tuple proposal
console.log(proposal.keywords[1]); // tc39

// Spread like objects!
const proposal2 = #{
  ...proposal,
  title: "Stage 2: Record & Tuple",
};
console.log(proposal2.title); // Stage 2: Record & Tuple
console.log(proposal2.keywords[1]); // tc39

// Object functions work on Records:
console.log(Object.keys(proposal)); // ["contents", "id", "keywords", "title"]
複製代碼

最後

以上筆者列舉了一部分有意思的 TC39 提案,除了以上這些還有不少提案,各位讀者有興趣的話能夠在 TC39 中尋找。

相關文章
相關標籤/搜索