跳到主要内容

过去的 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 现在包含这些助手,可能使用不同的语法。