Взаимодействие с JavaScript
Kotlin/Wasm позволяет использовать как код JavaScript из Kotlin, так и код Kotlin из JavaScript.
Компилятор Kotlin/JS уже предоставляет возможность транспилировать ваш код Kotlin в JavaScript. Взаимодействие Kotlin/Wasm с JavaScript разработано аналогичным образом, учитывая, что JavaScript — язык динамической типизации, в отличие от Kotlin. Следуйте нашему руководству, чтобы настроить взаимодействие в ваших проектах.
Помните, что Kotlin/Wasm всё ещё экспериментальный, и некоторые функции ещё не поддерживаются. Мы планируем улучшить взаимодействие с JavaScript, реализовав некоторые недостающие функции или аналогичную функциональность.
Использование кода JavaScript из Kotlin
Модификатор external
Для доступа к объявлениям JavaScript, определённым в глобальной области видимости, пометьте их модификатором external. Рассмотрим этот пример кода JavaScript:
// JavaScript
function consoleLogExample() {
console.log("Hello");
}
let externalInt = 0;
let Counter = {
value: 0,
step: 1,
increment() {
this.value += this.step;
}
};
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea();
}
calcArea() {
return this.height * this.width;
}
}
Вот как вы можете использовать этот код JavaScript в Kotlin:
// Kotlin/Wasm
// Use external functions to call JS functions defined in global scope
external fun consoleLogExample(): Unit
// In addition to functions, you can have external top-level properties
external var externalInt: Int
// External objects
external object Counter {
fun increment(): Unit
val value: Int
var step: Int
}
// External class
external class Rectangle(height: Double, width: Double) {
val height: Double
val width: Double
val area: Double
fun calcArea(): Double
}
Полный код см. в примере проекта Kotlin/Wasm браузер.
Аннотация @JsFun
Для включения небольшого фрагмента кода JS в ваш модуль Kotlin/Wasm используйте аннотацию @JsFun с внешними функциями верхнего уровня. Аргумент аннотации должен быть строкой с кодом JS, который вычисляет функцию с соответствующей сигнатурой:
@JsFun("function count(x) { return x + 10; }")
external fun count(x: Int): Int
Для краткости используйте синтаксис со стрелками:
@JsFun("x => x + 10")
external fun count(x: Int): Int
Компилятор Kotlin не проверяет эти фрагменты кода JavaScript и вычисляет их как есть. Синтаксические ошибки, если они есть, будут сообщены при выполнении вашего JavaScript.
@JsModule
Чтобы указать, что класс, пакет, функция или свойство external является модулем JavaScript, используйте @JsModule аннотацию. Рассмотрим этот пример кода JavaScript:
// jsModule.mjs
let maxUsers = 10;
function getActiveUsers() {
return 10;
};
class User {
constructor(maxUsers) {
this.maxUsers = maxUsers;
}
}
export {maxUsers, getActiveUsers, User};
Вот как вы можете использовать этот код JavaScript в Kotlin:
// kotlin
@file:JsModule("./jsModule.mjs")
package example
external val maxUsers: Int
external fun getActiveUsers(): Int
external class User {
constructor(username: String)
val username : String
}
Использование кода Kotlin из JavaScript
Аннотация @JsExport
Чтобы сделать объявление Kotlin/Wasm доступным из JavaScript, используйте аннотацию @JsExport с внешними функциями верхнего уровня:
// Kotlin/Wasm @JsExport fun addOne(x: Int): Int = x + 1
Теперь вы можете использовать эту функцию из JavaScript следующим образом:
// JavaScript import exports from "module.mjs" exports.addOne(10)
Функции, помеченные аннотацией @JsExport, отображаются как свойства в default экспорте сгенерированного .mjs модуля. Kotlin типы в JavaScript В Kotlin/JS значения реализуются внутренне как примитивы и объекты JavaScript. Они передаются в JavaScript и из него без обертки или копирования.
Однако в Kotlin/Wasm объекты имеют другое представление и не взаимозаменяемы с JavaScript. При передаче объекта Kotlin в JavaScript он по умолчанию рассматривается как пустой непрозрачный объект.
Единственное, что вы можете сделать, это сохранить его и передать объекты Kotlin обратно в Wasm. Однако для примитивных типов Kotlin/Wasm может адаптировать эти значения, чтобы они были полезны в JavaScript, путем копирования или обертки. Для повышения эффективности это делается статически. Важно, чтобы эти специальные конкретные типы присутствовали в сигнатурах функций. Например:
external fun convertIntAndString(num: Int, text: String)
external fun convertAnyAndChars(num: Any, text: CharSequence)
// ...
convertIntAndString(10, "Hello") // Converts Int and String to JS Number and String
convertAnyAndChars(10, "Hello") // No conversion
// values are passed as opaque references to Wasm objects
Типы Kotlin в JavaScript
Поддерживаемые типы
Посмотрите, как типы Kotlin отображаются в JavaScript:
Kotlin |
JavaScript |
Комментарии |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Содержимое строки копируется. В будущем предложение stringref может позволить нулевую копию взаимодействия строк. |
|
Неопределено |
Только при не-nullable и в функциях, возвращающих позицию. |
Тип функции, например ( |
Ссылка на функцию |
Параметры и возвращаемые значения типов функций следуют тем же правилам преобразования типов. |
|
Любое JS значение с заданными свойствами |
|
|
Соответствующий JS класс |
|
Другие типы Kotlin |
Не поддерживается |
Сюда входят типы |
Nullable |
Тип / |
|
Параметры типа |
Тот же, что и верхняя граница |
В объявлениях взаимодействия поддерживаются только внешние типы, такие как |
Обработка исключений
Выражение Kotlin/Wasm try-catch не может перехватывать исключения JavaScript.
Если вы попытаетесь использовать JavaScript try-catch выражение для перехвата исключений Kotlin/Wasm, оно будет выглядеть как общее WebAssembly.Exception без прямого доступа к сообщениям и данным.
Обходные пути для функций Kotlin/JS, не поддерживаемых в Kotlin/Wasm
Динамический тип
Kotlin/JS динамический тип, используемый для взаимодействия с неопределёнными или слабо типизированными объектами, пока не поддерживается. Во многих случаях можно использовать внешние интерфейсы и аннотацию @JsFun вместо этого:
// Kotlin/JS
val user: dynamic
val age: Int = 0
user.profile.updateAge(age);
// Kotlin/Wasm
external interface User
@JsFun("(user, age) => user.profile.updateAge(age)")
external fun updateUserAge(user: User, age: Int)
val user: User
val age: Int = 0
updateUserAge(user, age);
Встраивание JavaScript
Функция js(), используемая для встраивания кода JavaScript в код Kotlin, пока не поддерживается. Используйте аннотацию @JsFun вместо этого:
// Kotlin/JS
fun jsTypeOf(obj: Any): String {
return js("typeof obj")
}
// Kotlin/Wasm
@JsFun("(obj) => typeof obj")
external fun jsTypeOf(obj: SomeExternalInterfaceType): String
Расширение внешних интерфейсов и классов не внешними классами
Расширение классов JavaScript и использование внешних интерфейсов пока не поддерживается. Используйте аннотацию @JsFun вместо этого:
external interface DataProcessor {
fun processData(input: String): String
fun processResult(input: String): String
}
class DataHandler(val handlerData: String) {
fun processData(input: String): String = input + handlerData
fun processResult(input: String): String = handlerData + input
}
@JsFun("(processData, processResult) => ({ processData, processResult })")
external fun createDataProcessor(
processData: (String) -> String,
processResult: (String) -> String
): DataProcessor
fun convertHandlerToProcessor(handler: DataHandler): DataProcessor =
createDataProcessor(
processData = { input -> handler.processData(input) },
processResult = { input -> handler.processResult(input) }
)
© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/wasm-js-interop.html