跳到主要內容

過去的 JS 互操作

本頁面討論了 Dart 之前版本的 JS 互操作,這些版本已被視為遺留版本,並自 Dart 3.7 起已棄用。因此,未來請優先使用 dart:js_interop,並在可能的情況下遷移舊的互操作庫用法。雖然 dart:html 和其他 Web 庫密切相關,但它們在 package:web 頁面中介紹。

dart:js

#

dart:js 公開了一個具體的物件包裝器用於與 JS 物件進行互操作。此包裝器包含基於字串的方法,用於動態獲取、設定和呼叫被包裝 JS 物件上的屬性。由於包裝成本較高且人體工程學上使用更困難,其效能較低。例如,你無法獲得程式碼補全,因為你無法宣告互操作成員,而是依賴字串。dart:js 中公開的許多功能,如 allowInterop,後來透過其他互操作庫重新公開。

自從 package:jsdart:js_util 釋出以來,此庫已成為遺留庫。

package:js

#

package:js 引入了宣告互操作型別和成員的功能。它允許使用者編寫互操作類而不是互操作擴充套件型別。在執行時,這些類被擦除為類似於 dart:js_interopJSObject 的型別。

dart
@JS()
class JSType {}

package:js 的使用者會發現 dart:js_interop 的語法和語義很熟悉。你可能可以透過將類定義替換為擴充套件型別並使其在許多情況下工作來遷移到 dart:js_interop

然而,存在顯著差異:

  • package:js 型別不能用於與瀏覽器 API 進行互操作。dart:js_interop 型別可以。
  • package:js 允許動態分派。這意味著如果你將 package:js 型別轉換為 dynamic 並在其上呼叫互操作成員,它將轉發到正確的成員。這在 dart:js_interop 中不再可能。
  • package:js@JS 沒有健全性保證,因為 external 成員的返回型別未被檢查。dart:js_interop 是健全的。
  • package:js 型別不能重新命名例項成員或擁有非 external 成員。
  • package:js 型別可以子型別化併成為非互操作類的超型別。這通常用於模擬。使用 dart:js_interop,模擬是透過替換 JS 物件來完成的。請參閱模擬教程
  • @anonymous 型別是一種使用物件字面量建構函式宣告互操作型別的方式。dart:js_interop 不以這種方式區分型別,並且任何 external 具名引數建構函式都是物件字面量建構函式。

@staticInterop

#

@JS@anonymous 一起,package:js 後來公開了 @staticInterop,它是互操作擴充套件型別的原型。它與 dart:js_interop 一樣具有表達性和限制性,旨在作為擴充套件型別可用之前的過渡語法。

@staticInterop 型別隱式地被擦除為 JSObject。它要求使用者在擴充套件中宣告所有例項成員,以便只能使用靜態語義,並且具有更強的健全性保證。使用者可以使用它與瀏覽器 API 互動,它也允許重新命名和非 external 成員等。與互操作擴充套件型別一樣,它不支援動態分派。

@staticInterop 類幾乎總是可以透過簡單地將類更改為擴充套件型別並刪除註解來遷移到互操作擴充套件型別。

dart:js_interop 公開 @staticInterop(以及 @anonymous,但僅在也使用 @staticInterop 時)以支援靜態互操作語義,直到擴充套件型別被新增到語言中。所有此類型別現在都應遷移到擴充套件型別。

dart:js_util

#

dart:js_util 提供了許多無法在 package:js 型別中宣告或對於值雙向傳遞所必需的實用函式。這包括諸如:

  • allowInterop(現在是 Function.toJS
  • getProperty/setProperty/callMethod/callConstructor(現在在 dart:js_interop_unsafe 中)
  • 各種 JS 運算子
  • 型別檢查助手
  • 模擬支援
  • 等等。

dart:js_interopdart:js_interop_unsafe 現在包含這些助手,可能使用不同的語法。