首頁 > 後端開發 > Python教學 > Python 化 JavaScript

Python 化 JavaScript

Mary-Kate Olsen
發布: 2025-01-14 22:19:48
原創
945 人瀏覽過

Pythonizing JavaScript

Python 擁有許多強大的實用函數,例如 rangeenumeratezip 等,這些函數基於可迭代物件和迭代器協定建構。結合生成器函數,這些協議自 2016 年左右起就在所有 Evergreen 瀏覽器和 Node.js 中可用,但在我看來,它們的使用率卻低得令人吃驚。在這篇文章中,我將使用 TypeScript 實作其中一些輔助函數,希望能改變這個現狀。

迭代器、可迭代物件和生成器函數

迭代器協定

迭代器協定是一種產生值序列的標準方法。要使一個物件成為迭代器,它必須透過實作 next 方法來遵守迭代器協議,例如:

<code class="language-typescript">const iterator = {
  i: 0,
  next() {
    return { done: false, value: this.i++ };
  }
};</code>
登入後複製
登入後複製

然後,我們可以重複呼叫 next 方法來取得值:

<code class="language-typescript">console.log(iterator.next().value); // → 0
console.log(iterator.next().value); // → 1
console.log(iterator.next().value); // → 2
console.log(iterator.next().value); // → 3
console.log(iterator.next().value); // → 4</code>
登入後複製
登入後複製

next 方法應該傳回一個對象,該物件包含一個 value 屬性(包含實際值)和一個 done 屬性(指定迭代器是否已耗盡,即是否無法再產生值)。根據 MDN 的說法,這兩個屬性都不是嚴格必需的,如果兩者都缺失,則傳回值被視為 { done: false, value: undefined }

可迭代物件協定

可迭代物件協定允許物件定義其自身的迭代行為。要遵守可迭代物件協議,物件必須使用 Symbol.iterator 鍵定義一個方法,該方法傳回一個迭代器。許多內建物件(如 ArrayTypedArraySetMap)都實現了此協議,因此可以使用 for...of 循環對其進行迭代。

例如,對於數組,values 方法被指定為數組的 Symbol.iterator 方法:

<code class="language-typescript">console.log(Array.prototype.values === Array.prototype[Symbol.iterator]); // → true</code>
登入後複製
登入後複製

我們可以結合迭代器和可迭代物件協定來建立一個可迭代的迭代器,如下所示:

<code class="language-typescript">const iterable = {
  i: 0,
  [Symbol.iterator]() {
    const iterable = this;
    return {
      next() {
        return { done: false, value: iterable.i++ };
      }
    };
  }
};</code>
登入後複製
登入後複製

這兩個協議的名稱不幸地非常相似,至今仍然讓我感到困惑。

正如您可能猜到的那樣,我們的迭代器和可迭代物件範例是無限的,這意味著它們可以永遠生成值。這是一個非常強大的特性,但也容易成為一個陷阱。例如,如果我們要在一個for...of 循環中使用可迭代對象,則循環將永遠持續下去;或者用作Array.from 的參數,JS 最終會拋出一個RangeError,因為數組會變得太大:

<code class="language-typescript">// 将无限循环:
for (const value of iterable) {
  console.log(value);
}

// 将抛出 RangeError
const arr = Array.from(iterable);</code>
登入後複製
登入後複製

迭代器和可迭代物件甚至可以無限的原因是它們是惰性求值的,即只有在使用時才會產生值。

生成器函數

雖然迭代器和可迭代物件是寶貴的工具,但編寫起來有點麻煩。作為替代方案,引入了生成器函數。

產生器函數使用function* (或function *,星號可以在function 關鍵字和函數名稱之間任意位置)指定,允許我們中斷函數的執行,使用yield 關鍵字傳回值,並在稍後繼續中斷的地方繼續執行,同時保持其內部狀態:

<code class="language-typescript">const iterator = {
  i: 0,
  next() {
    return { done: false, value: this.i++ };
  }
};</code>
登入後複製
登入後複製

Python 實用程式

如引言中所述,Python 有一些非常有用的內建實用程序,它們基於上述協定。 JavaScript 最近也為迭代器增加了一些輔助方法,例如 .drop().filter(),但(也許還沒有)擁有 Python 中一些更有趣的實用程式。

讓我們動手實踐吧!

現在理論部分已經結束,讓我們開始實作一些 Python 函數吧!

注意:此處顯示的這些實作都不應原樣用於生產環境。 它們缺乏錯誤處理和邊界條件檢查。

enumerate(iterable [,start])

Python 中的 enumerate 為輸入序列或可迭代物件中的每個項目傳回一系列元組,其中第一個位置包含計數,第二個位置包含項目:

<code class="language-typescript">console.log(iterator.next().value); // → 0
console.log(iterator.next().value); // → 1
console.log(iterator.next().value); // → 2
console.log(iterator.next().value); // → 3
console.log(iterator.next().value); // → 4</code>
登入後複製
登入後複製

enumerate 也接受一個可選的 start 參數,指示計數器應從何處開始:

<code class="language-typescript">console.log(Array.prototype.values === Array.prototype[Symbol.iterator]); // → true</code>
登入後複製
登入後複製

讓我們使用生成器函數在 TypeScript 中實現它。我們可以使用 python 文件中概述的實作作為指導

<code class="language-typescript">const iterable = {
  i: 0,
  [Symbol.iterator]() {
    const iterable = this;
    return {
      next() {
        return { done: false, value: iterable.i++ };
      }
    };
  }
};</code>
登入後複製
登入後複製

由於 JavaScript 中的字串實現了可迭代物件協議,我們可以簡單地將字串傳遞給我們的 enumerate 函數並像這樣調用它:

<code class="language-typescript">// 将无限循环:
for (const value of iterable) {
  console.log(value);
}

// 将抛出 RangeError
const arr = Array.from(iterable);</code>
登入後複製
登入後複製

repeat(elem [,n])

repeat 是內建 itertools 函式庫的一部分,它重複給定的輸入 elem n 次,如果未指定 n,則無限重複。我們再次可以將 python 文件中的實作作為起點。

<code class="language-typescript">function* sequence() {
  let i = 0;
  while (true) {
    yield i++;
  }
}

const seq = sequence();
console.log(seq.next().value); // → 0;
console.log(seq.next().value); // → 1;
console.log(seq.next().value); // → 2;

// 将无限循环,从 3 开始
for (const value of seq) {
  console.log(value);
}</code>
登入後複製

(此處省略了 cyclerange 函數的實現,因為篇幅過長,但其邏輯與原文相同,只是將程式碼用 TypeScript 重寫)

結論

這是我的第一篇部落格文章,我希望您覺得它有趣,也許您會在未來的專案中使用迭代器、可迭代物件和生成器。如果您有任何疑問或需要澄清,請留下評論,我很樂意提供更多資訊。

要注意的是,與使用計數器的原始 for 循環相比,效能相差甚遠。這在許多情況下可能無關緊要,但在高性能場景中絕對很重要。當我將 PCM 資料繪製到畫布上並使用迭代器和生成器時,發現幀丟失了,這讓我很苦惱。事後看來這可能是顯而易見的,但當時對我來說卻並非如此 :D

乾杯!

以上是Python 化 JavaScript的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板