在 JavaScript 中使用 Kotlin 代码
根据选择的 JavaScript 模块 系统不同, Kotlin/JS 编译期会产生不同的输出. 但通常 Kotlin 编译器会生成通常的 JavaScript 类, 函数, 和属性, 你可以在 JavaScript 代码中自由地使用它们. 但是, 有一些细节问题, 你需要记住.
将声明隔离在 plain 模式下的独立 JavaScript 对象内
如果你将模块类型明确设置为 plain
, Kotlin 会创建一个对象, 其中包含来自当前模块的所有 Kotlin 声明, 以免破坏全局对象. 因此, 对于模块 myModule
, 在 JavaScript 中可以通过 myModule
对象访问到所有的声明. 比如:
在 JavaScript 中可以这样调用:
如果你将你的 Kotlin 模块编译为 JavaScript 模块, 比如 UMD, CommonJS 或 AMD (对编译目标 browser
和 nodejs
, 默认设定是 UMD), 就会出现兼容问题. 这种情况下, 你的声明对外公开时使用的格式将由你选择的 JavaScript 模块系统决定. 比如, 如果使用 UMD 或 CommonJS, 那么需要这样来使用你的代码:
关于 JavaScript 模块系统, 更多详情请参见 JavaScript 模块(Module).
包结构
Kotlin 会将它的包结构公开到 JavaScript 中, 因此, 除非你将你的声明定义在最顶层包中, 否则在 JavaScript 中就必须使用完整限定名来访问你的声明. 比如:
比如, 如果使用 UMD 或 CommonJS, 那么调用端应该如下:
如果模块系统使用 plain
模式, 那么应该是:
@JsName 注解
某些情况下 (比如, 为了支持重载(overload)), Kotlin 编译器会对 JavaScript 代码中生成的函数和属性的名称进行混淆. 为了控制编译器生成的函数和属性名称, 你可以使用 @JsName
注解:
然后, 你可以在 JavaScript 中通过以下方式来使用这个类:
如果我们不指定 @JsName
注解, 那么编译器将会根据函数签名计算得到一个后缀字符串, 添加到生成的函数名末尾, 比如 hello_61zpoe$
.
注意, 有些情况下 Kotlin 编译器不会进行这样的名称混淆:
对
external
声明, 不会进行名称混淆.从
external
类继承的非external
类之内, 被覆盖的函数, 不会进行名称混淆.
@JsName
注解的参数要求是字面值的字符串常量, 而且必须是一个有效的标识符. 如果将非标识符字符串用于 @JsName
注解, 编译器会报告错误. 下面的示例会常数一个编译期错误:
@JsExport 注解
对一个顶级声明 (比如一个类或函数)使用 @JsExport
注解, 就可以在 JavaScript 中访问 Kotlin 声明. 这个注解会使用 Kotlin 中给定的名称, 导出所有的下层声明. 使用 @file:JsExport
的方式, 还可以将这个注解应用于整个源代码文件.
为了在导出声明时解决名称的歧义(比如同名函数的重载(overload)), 可以将 @JsExport
注解和 @JsName
注解一起使用, 用来指定生成和导出的函数名称.
在当前的 IR compiler backend 中, 要让你的函数在 Kotlin 中可以使用, 唯一的方法是使用 @JsExport
注解.
对于跨平台项目, 在共通代码中也可以使用 @JsExport
. 它只在针对 JavaScript 目标进行编译时才起作用, 并且允许你导出那些平台无关的 Kotlin 声明.
@JsStatic
@JsStatic
注解告诉编译器为它指定的声明生成额外的静态方法. 这可以帮助你在 JavaScript 中直接使用你的 Kotlin 代码中的静态成员.
你可以将 @JsStatic
注解用于命名对象中定义的函数, 以及在类和接口之内声明的同伴对象中定义的函数. 如果你使用这个注解, 编译器会生成对象的静态方法, 以及对象本身的实例方法. 例如:
现在, callStatic()
函数会成为 JavaScript 中的静态函数, 而 callNonStatic()
函数则不是:
也可以将 @JsStatic
注解用于对象或同伴对象的属性, 这样会将它的 get 方法和 set 方法变成这个对象的静态成员, 或者包含这个同伴对象的类的静态成员.
JavaScript 中的 Kotlin 类型
Kotlin 类型在 JavaScript 中映射为以下类型:
Kotlin 类型 | JavaScript 类型 | 注释 |
---|---|---|
|
| |
|
| Number 表示字符的编码. |
| 不支持 | JavaScript 中没有 64 位整数类型, 因此它使用一个 Kotlin 类来模拟. |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| 包含属性 |
|
| |
|
| |
|
| 包含属性 |
|
| 包含属性 |
|
| 通过 |
|
| 通过 |
|
| 通过 |
| Undefined | 用作返回类型时可以导出, 用作参数类型时不可以导出. |
|
| |
|
| |
可为 Null 的 |
| |
Kotlin 的所有其他类型 (使用 | 不支持 | 包含 Kotlin 的 无符号整数类型. |
此外, 还要注意:
Kotlin 为
kotlin.Int
,kotlin.Byte
,kotlin.Short
,kotlin.Char
和kotlin.Long
保留了溢出语义.Kotlin 在运行时无法区分数值类型(除
kotlin.Long
外), 因此以下代码能够正常工作:fun f() { val x: Int = 23 val y: Any = x println(y as Float) }Kotlin 在 JavaScript 中保留了延迟加载对象的初始化处理.
Kotlin 在 JavaScript 中没有实现顶级属性的延迟加载初始化处理.