syscall/js 包详解
概述
syscall/js 包在使用 js/wasm 架构时提供对 WebAssembly 主机环境的访问。其 API 基于 JavaScript 语义。
核心功能:
- JavaScript 对象访问和操作
- Go 与 JavaScript 函数互调用
- 类型转换(Go ↔ JavaScript)
- DOM 事件处理
- WebAssembly 宿主环境交互
重要说明:
- ⚠️ 实验性:此包是 EXPERIMENTAL,可能发生变化
- ⚠️ 平台限制:仅适用于 js/wasm 架构(GOOS=js, GOARCH=wasm)
- ⚠️ 不兼容保证:不受 Go 兼容性承诺保护
- ⚠️ 资源管理:Func 必须调用 Release 释放资源
包导入
import "syscall/js"
常量
Type 类型常量
const (
TypeUndefined Type = iota // undefined
TypeNull // null
TypeBoolean // boolean
TypeNumber // number
TypeString // string
TypeSymbol // symbol
TypeObject // object
TypeFunction // function
)
功能: 表示 JavaScript 值的类型。
类型详解(按 A-Z 分类)
E
Error
type Error struct {
Value
}
功能: 包装 JavaScript 错误。
方法:
Error() string- 实现 error 接口
示例:
package main
import (
"syscall/js"
)
func main() {
// 触发 JavaScript 错误
result, err := js.Global().Call("nonExistentFunction")
if err != nil {
jsErr, ok := err.(js.Error)
if ok {
println("JS 错误:", jsErr.Error())
}
}
_ = result
}
F
Func
type Func struct {
Value
}
功能: 包装 Go 函数供 JavaScript 调用。
重要说明:
- 从 JavaScript 调用包装的 Go 函数会暂停事件循环并启动新的 goroutine
- 在 Go 调用 JavaScript 期间触发的其他包装函数在同一 goroutine 上执行
- 如果一个包装函数阻塞,JavaScript 事件循环会被阻塞直到该函数返回
- 调用异步 JavaScript API(如 fetch)会导致死锁
- 阻塞函数应显式启动新的 goroutine
- 必须调用 Release 释放资源
方法:
Release()- 释放资源
示例:
package main
import (
"syscall/js"
)
func main() {
// 创建 Go 函数供 JS 调用
callback := js.FuncOf(func(this js.Value, args []js.Value) any {
println("JS 调用了 Go 函数")
if len(args) > 0 {
println("参数:", args[0].String())
}
return nil
})
// 设置到全局
js.Global().Set("goCallback", callback)
// 使用完成后释放
defer callback.Release()
// 防止程序退出
select {}
}
FuncOf
func FuncOf(fn func(this Value, args []Value) any) Func
功能: 返回一个供 JavaScript 使用的函数。
参数:
fn func(this Value, args []Value) any- Go 函数this- JavaScript 的 this 关键字args- 调用参数- 返回值通过 ValueOf 映射回 JavaScript
返回值:
Func- 包装后的函数
注意:
- 必须调用 Release 释放资源
示例:
package main
import (
"syscall/js"
)
func add(this js.Value, args []js.Value) any {
if len(args) != 2 {
return js.Undefined()
}
a := args[0].Int()
b := args[1].Int()
return a + b
}
func main() {
addFunc := js.FuncOf(add)
js.Global().Set("add", addFunc)
defer addFunc.Release()
select {}
}
T
Type
type Type uint8
功能: 表示 JavaScript 值的类型。
方法:
String() string- 返回类型的字符串表示
示例:
package main
import (
"fmt"
"syscall/js"
)
func main() {
v := js.Global().Get("console")
t := v.Type()
fmt.Println("类型:", t) // object
fmt.Println("类型字符串:", t.String())
}
V
Value
type Value struct {
// 包含过滤或未导出的字段
}
功能: 表示 JavaScript 值。零值是 JavaScript 的 “undefined”。
重要说明:
- 值可以使用 Equal 方法检查相等性
- 不能直接用 == 比较
方法:
Bool() bool- 转换为 boolCall(m string, args ...any) Value- 调用方法Delete(p string)- 删除属性Equal(w Value) bool- 检查相等性Float() float64- 转换为 float64Get(p string) Value- 获取属性Index(i int) Value- 获取索引InstanceOf(t Value) bool- instanceof 检查Int() int- 转换为 intInvoke(args ...any) Value- 调用函数IsNaN() bool- 检查 NaNIsNull() bool- 检查 nullIsUndefined() bool- 检查 undefinedLength() int- 获取 length 属性New(args ...any) Value- 使用 new 运算符Set(p string, x any)- 设置属性SetIndex(i int, x any)- 设置索引String() string- 转换为字符串Truthy() bool- 检查真值Type() Type- 获取类型
示例:
package main
import (
"syscall/js"
)
func main() {
// 获取全局对象
global := js.Global()
// 获取 window 对象
window := global.Get("window")
// 获取属性
console := global.Get("console")
// 调用方法
console.Call("log", "Hello from Go!")
// 设置属性
global.Set("myVar", 42)
// 调用函数
alert := global.Get("alert")
alert.Invoke("Alert from Go!")
}
ValueOf
func ValueOf(x any) Value
功能: 将 Go 值转换为 JavaScript 值。
参数:
x any- Go 值
返回值:
Value- JavaScript 值
类型映射:
| Go | JavaScript |
|---|---|
| js.Value | [its value] |
| js.Func | function |
| nil | null |
| bool | boolean |
| integers and floats | number |
| string | string |
| []interface{} | new array |
| map[string]interface{} | new object |
注意:
- 如果 x 不是预期类型会 panic
示例:
package main
import (
"syscall/js"
)
func main() {
// 基本类型
js.Global().Set("num", js.ValueOf(42))
js.Global().Set("str", js.ValueOf("hello"))
js.Global().Set("bool", js.ValueOf(true))
// 数组
arr := []interface{}{1, 2, 3}
js.Global().Set("myArray", js.ValueOf(arr))
// 对象
obj := map[string]interface{}{
"name": "Alice",
"age": 25,
}
js.Global().Set("myObject", js.ValueOf(obj))
}
Value.Bool
func (v Value) Bool() bool
功能: 将值 v 作为 bool 返回。
注意:
- 如果 v 不是 JavaScript boolean 会 panic
示例:
b := js.Global().Get("someBool").Bool()
Value.Call
func (v Value) Call(m string, args ...any) Value
功能: 调用值 v 的方法 m。
参数:
m string- 方法名args ...any- 参数
返回值:
Value- 返回值
注意:
- 如果 v 没有方法 m 会 panic
- 参数根据 ValueOf 映射到 JavaScript
示例:
// console.log("Hello")
js.Global().Get("console").Call("log", "Hello")
// array.push(1)
array.Get("array").Call("push", 1)
Value.Delete
func (v Value) Delete(p string)
功能: 删除值 v 的 JavaScript 属性 p。
参数:
p string- 属性名
注意:
- 如果 v 不是 JavaScript object 会 panic
Value.Equal
func (v Value) Equal(w Value) bool
功能: 根据 JavaScript 的 === 运算符报告 v 和 w 是否相等。
示例:
v1 := js.Global().Get("obj1")
v2 := js.Global().Get("obj2")
if v1.Equal(v2) {
println("相等")
}
Value.Float
func (v Value) Float() float64
功能: 将值 v 作为 float64 返回。
注意:
- 如果 v 不是 JavaScript number 会 panic
Value.Get
func (v Value) Get(p string) Value
功能: 返回值 v 的 JavaScript 属性 p。
参数:
p string- 属性名
返回值:
Value- 属性值
注意:
- 如果 v 不是 JavaScript object 会 panic
示例:
// 获取 document
doc := js.Global().Get("document")
// 获取 window.location
location := js.Global().Get("window").Get("location")
// 获取嵌套属性
hostname := location.Get("hostname")
Value.Index
func (v Value) Index(i int) Value
功能: 返回值 v 的 JavaScript 索引 i。
参数:
i int- 索引
返回值:
Value- 索引处的值
注意:
- 如果 v 不是 JavaScript object 会 panic
示例:
array := js.Global().Get("myArray")
first := array.Index(0)
second := array.Index(1)
Value.InstanceOf
func (v Value) InstanceOf(t Value) bool
功能: 根据 JavaScript 的 instanceof 运算符报告 v 是否是 t 的实例。
示例:
array := js.Global().Get("myArray")
arrayConstructor := js.Global().Get("Array")
if array.InstanceOf(arrayConstructor) {
println("是 Array 实例")
}
Value.Int
func (v Value) Int() int
功能: 将值 v 截断为 int 返回。
注意:
- 如果 v 不是 JavaScript number 会 panic
Value.Invoke
func (v Value) Invoke(args ...any) Value
功能: 调用值 v(作为函数)。
参数:
args ...any- 参数
返回值:
Value- 返回值
注意:
- 如果 v 不是 JavaScript 函数会 panic
- 参数根据 ValueOf 映射到 JavaScript
示例:
// 调用全局函数
parseInt := js.Global().Get("parseInt")
result := parseInt.Invoke("42")
println(result.Int()) // 42
// 调用 setTimeout
setTimeout := js.Global().Get("setTimeout")
setTimeout.Invoke(js.FuncOf(func(this js.Value, args []js.Value) any {
println("Timeout!")
return nil
}), 1000)
Value.IsNaN
func (v Value) IsNaN() bool
功能: 报告 v 是否是 JavaScript 值 “NaN”。
Value.IsNull
func (v Value) IsNull() bool
功能: 报告 v 是否是 JavaScript 值 “null”。
Value.IsUndefined
func (v Value) IsUndefined() bool
功能: 报告 v 是否是 JavaScript 值 “undefined”。
Value.Length
func (v Value) Length() int
功能: 返回 v 的 JavaScript 属性 “length”。
注意:
- 如果 v 不是 JavaScript object 会 panic
示例:
array := js.Global().Get("myArray")
length := array.Length()
println("数组长度:", length)
str := js.Global().Get("myString")
length = str.Length()
println("字符串长度:", length)
Value.New
func (v Value) New(args ...any) Value
功能: 使用 JavaScript 的 “new” 运算符。
参数:
args ...any- 构造函数参数
返回值:
Value- 新创建的对象
注意:
- 如果 v 不是 JavaScript 函数会 panic
- 参数根据 ValueOf 映射到 JavaScript
示例:
// new Date()
dateConstructor := js.Global().Get("Date")
date := dateConstructor.New()
// new Array(10)
arrayConstructor := js.Global().Get("Array")
array := arrayConstructor.New(10)
Value.Set
func (v Value) Set(p string, x any)
功能: 将值 v 的 JavaScript 属性 p 设置为 ValueOf(x)。
参数:
p string- 属性名x any- 属性值
注意:
- 如果 v 不是 JavaScript object 会 panic
示例:
// 设置全局变量
js.Global().Set("myVar", 42)
js.Global().Set("myString", "hello")
// 设置对象属性
obj := js.Global().Get("myObject")
obj.Set("name", "Alice")
obj.Set("age", 25)
Value.SetIndex
func (v Value) SetIndex(i int, x any)
功能: 将值 v 的 JavaScript 索引 i 设置为 ValueOf(x)。
参数:
i int- 索引x any- 值
注意:
- 如果 v 不是 JavaScript object 会 panic
示例:
array := js.Global().Get("myArray")
array.SetIndex(0, 1)
array.SetIndex(1, 2)
array.SetIndex(2, 3)
Value.String
func (v Value) String() string
功能: 将值 v 作为字符串返回。
注意:
- 如果 v 的 Type 不是 TypeString 不会 panic
- 返回形式为 “
” 或 “<T: V>” 的字符串
示例:
str := js.Global().Get("myString").String()
println("字符串:", str)
// 非字符串类型
num := js.Global().Get("myNumber")
str = num.String() // 返回值的字符串表示
Value.Truthy
func (v Value) Truthy() bool
功能: 报告 v 在 JavaScript 布尔上下文中是否为真。
JavaScript 假值:
- undefined
- null
- false
- 0
- NaN
- “”(空字符串)
示例:
v := js.Global().Get("someValue")
if v.Truthy() {
println("真值")
} else {
println("假值")
}
Value.Type
func (v Value) Type() Type
功能: 返回值 v 的 JavaScript 类型。
返回值:
Type- JavaScript 类型
注意:
- 类似于 JavaScript 的 typeof 运算符
- 对 null 返回 TypeNull 而不是 TypeObject
ValueError
type ValueError struct {
Method string
Type Type
}
功能: 当在 Value 上调用不支持的方法时发生。
方法:
Error() string- 实现 error 接口
函数详解(按 A-Z 分类)
C
CopyBytesToGo
func CopyBytesToGo(dst []byte, src Value) int
功能: 从 src 复制字节到 dst。
参数:
dst []byte- 目标字节切片src Value- JavaScript Uint8Array 或 Uint8ClampedArray
返回值:
int- 复制的字节数(src 和 dst 长度的最小值)
注意:
- 如果 src 不是 Uint8Array 或 Uint8ClampedArray 会 panic
示例:
package main
import (
"syscall/js"
)
func main() {
// 从 JavaScript 获取 Uint8Array
jsArray := js.Global().Get("myUint8Array")
// 创建 Go 字节切片
goBytes := make([]byte, jsArray.Length())
// 复制数据
n := js.CopyBytesToGo(goBytes, jsArray)
println("复制了", n, "字节")
}
CopyBytesToJS
func CopyBytesToJS(dst Value, src []byte) int
功能: 从 src 复制字节到 dst。
参数:
dst Value- JavaScript Uint8Array 或 Uint8ClampedArraysrc []byte- 源字节切片
返回值:
int- 复制的字节数(src 和 dst 长度的最小值)
注意:
- 如果 dst 不是 Uint8Array 或 Uint8ClampedArray 会 panic
示例:
package main
import (
"syscall/js"
)
func main() {
// 创建 JavaScript Uint8Array
arrayConstructor := js.Global().Get("Uint8Array")
jsArray := arrayConstructor.New(10)
// Go 字节数据
goBytes := []byte{1, 2, 3, 4, 5}
// 复制数据到 JS
n := js.CopyBytesToJS(jsArray, goBytes)
println("复制了", n, "字节")
}
G
Global
func Global() Value
功能: 返回 JavaScript 全局对象,通常是 “window”(浏览器)或 “global”(Node.js)。
返回值:
Value- 全局对象
示例:
package main
import (
"syscall/js"
)
func main() {
global := js.Global()
// 访问全局属性
console := global.Get("console")
document := global.Get("document")
// 调用全局方法
console.Call("log", "Hello from Go!")
}
N
Null
func Null() Value
功能: 返回 JavaScript 值 “null”。
返回值:
Value- null 值
示例:
js.Global().Set("myNull", js.Null())
U
Undefined
func Undefined() Value
功能: 返回 JavaScript 值 “undefined”。
返回值:
Value- undefined 值
示例:
js.Global().Set("myUndefined", js.Undefined())
典型示例
示例 1:基本 JavaScript 交互
package main
import (
"syscall/js"
)
func main() {
// 获取全局对象
global := js.Global()
// 获取 console 并调用 log
console := global.Get("console")
console.Call("log", "Hello from WebAssembly!")
// 设置全局变量
global.Set("goVar", 42)
global.Set("goString", "Hello")
// 获取属性
location := global.Get("location")
hostname := location.Get("hostname")
console.Call("log", "Hostname:", hostname)
}
示例 2:Go 函数供 JavaScript 调用
package main
import (
"syscall/js"
)
func add(this js.Value, args []js.Value) any {
if len(args) != 2 {
return js.Undefined()
}
a := args[0].Int()
b := args[1].Int()
return a + b
}
func greet(this js.Value, args []js.Value) any {
if len(args) == 0 {
return "Hello!"
}
name := args[0].String()
return "Hello, " + name + "!"
}
func main() {
// 导出函数到 JavaScript
js.Global().Set("add", js.FuncOf(add))
js.Global().Set("greet", js.FuncOf(greet))
console := js.Global().Get("console")
console.Call("log", "Go functions exported!")
// 防止程序退出
select {}
}
JavaScript 使用:
console.log(add(10, 20)); // 30
console.log(greet("Alice")); // "Hello, Alice!"
示例 3:操作 DOM
package main
import (
"syscall/js"
)
func main() {
document := js.Global().Get("document")
// 获取元素
body := document.Get("body")
// 创建元素
h1 := document.Call("createElement", "h1")
h1.Call("setAttribute", "id", "go-title")
h1.Set("innerHTML", "Hello from Go!")
// 添加到页面
body.Call("appendChild", h1)
// 修改样式
style := h1.Get("style")
style.Set("color", "blue")
style.Set("fontSize", "24px")
// 添加点击事件
h1.Set("onclick", js.FuncOf(func(this js.Value, args []js.Value) any {
js.Global().Get("console").Call("log", "Title clicked!")
return nil
}))
select {}
}
示例 4:处理异步操作
package main
import (
"syscall/js"
)
func handlePromise(this js.Value, args []js.Value) any {
if len(args) == 0 {
return js.Undefined()
}
promise := args[0]
// 创建 then 回调
thenCallback := js.FuncOf(func(this js.Value, args []js.Value) any {
js.Global().Get("console").Call("log", "Promise resolved:", args[0])
return nil
})
// 创建 catch 回调
catchCallback := js.FuncOf(func(this js.Value, args []js.Value) any {
js.Global().Get("console").Call("log", "Promise rejected:", args[0])
return nil
})
// 链式调用
promise.Call("then", thenCallback).Call("catch", catchCallback)
return nil
}
func main() {
js.Global().Set("handlePromise", js.FuncOf(handlePromise))
// JavaScript 可以这样调用:
// handlePromise(fetch('/api/data'))
select {}
}
示例 5:字节数据转换
package main
import (
"syscall/js"
)
func main() {
// Go 字节转 JavaScript Uint8Array
goData := []byte{1, 2, 3, 4, 5}
arrayConstructor := js.Global().Get("Uint8Array")
jsArray := arrayConstructor.New(len(goData))
// 复制到 JS
js.CopyBytesToJS(jsArray, goData)
js.Global().Set("myArray", jsArray)
// JavaScript Uint8Array 转 Go
jsArray2 := js.Global().Get("myArray")
goBytes := make([]byte, jsArray2.Length())
js.CopyBytesToGo(goBytes, jsArray2)
console := js.Global().Get("console")
console.Call("log", "Go bytes:", goBytes)
select {}
}
示例 6:事件处理
package main
import (
"syscall/js"
)
func main() {
document := js.Global().Get("document")
// 获取按钮
button := document.Call("getElementById", "myButton")
// 添加点击事件
clickHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
js.Global().Get("console").Call("log", "Button clicked!")
// 阻止默认行为
event := args[0]
event.Call("preventDefault")
return nil
})
button.Call("addEventListener", "click", clickHandler)
// 添加鼠标悬停事件
mouseHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
js.Global().Get("console").Call("log", "Mouse over!")
return nil
})
button.Call("addEventListener", "mouseover", mouseHandler)
select {}
}
示例 7:调用 JavaScript 库
package main
import (
"syscall/js"
)
func main() {
// 假设页面加载了 jQuery
$ := js.Global().Get("$")
// 使用 jQuery
$("body").Call("css", "background-color", "lightblue")
// 添加元素
$("<h1>").
Call("text", "jQuery from Go").
Call("appendTo", "body")
// 添加点击事件
$("button").Call("on", "click", js.FuncOf(func(this js.Value, args []js.Value) any {
js.Global().Get("console").Call("log", "Button clicked via jQuery")
return nil
}))
select {}
}
示例 8:与 JavaScript 双向通信
package main
import (
"syscall/js"
)
// 导出到 JavaScript 的函数
func jsCallback(this js.Value, args []js.Value) any {
if len(args) == 0 {
return nil
}
message := args[0].String()
js.Global().Get("console").Call("log", "JS 调用 Go:", message)
// 返回值给 JavaScript
return map[string]interface{}{
"status": "success",
"message": "处理完成:" + message,
}
}
func main() {
// 导出函数
js.Global().Set("goCallback", js.FuncOf(jsCallback))
// 调用 JavaScript 函数
jsCode := `
// 调用 Go 函数
const result = goCallback("Hello from JS");
console.log("Go 返回:", result);
`
js.Global().Call("eval", jsCode)
select {}
}
最佳实践
1. 正确管理资源
// ✅ 推荐:使用 defer 释放
callback := js.FuncOf(myFunc)
js.Global().Set("callback", callback)
defer callback.Release()
// ❌ 不推荐:忘记释放
callback := js.FuncOf(myFunc)
js.Global().Set("callback", callback)
// 资源泄漏
2. 避免阻塞事件循环
// ✅ 推荐:在 goroutine 中执行阻塞操作
js.Global().Set("handler", js.FuncOf(func(this js.Value, args []js.Value) any {
go func() {
// 阻塞操作
time.Sleep(time.Second)
}()
return nil
}))
// ❌ 不推荐:直接阻塞
js.Global().Set("handler", js.FuncOf(func(this js.Value, args []js.Value) any {
time.Sleep(time.Second) // 阻塞事件循环
return nil
}))
3. 错误处理
// ✅ 推荐:检查错误
result, err := js.Global().Call("someFunction")
if err != nil {
jsErr, ok := err.(js.Error)
if ok {
println("JS 错误:", jsErr.Error())
}
}
// ❌ 不推荐:忽略错误
result, _ := js.Global().Call("someFunction")
4. 类型安全
// ✅ 推荐:检查类型
v := js.Global().Get("myValue")
if v.Type() == js.TypeString {
str := v.String()
// 使用 str
}
// ❌ 不推荐:直接转换可能 panic
str := v.String() // 如果不是字符串会 panic
与其他包配合
与 encoding/json 配合
package main
import (
"encoding/json"
"syscall/js"
)
func main() {
// Go 结构体转 JavaScript 对象
data := map[string]interface{}{
"name": "Alice",
"age": 25,
}
jsonData, _ := json.Marshal(data)
var jsObj interface{}
json.Unmarshal(jsonData, &jsObj)
js.Global().Set("goData", js.ValueOf(jsObj))
// JavaScript 对象转 Go
jsData := js.Global().Get("jsData")
// 需要通过回调获取数据
}
与 context 配合
package main
import (
"context"
"syscall/js"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
// 创建取消按钮
document := js.Global().Get("document")
button := document.Call("getElementById", "cancelBtn")
button.Set("onclick", js.FuncOf(func(this js.Value, args []js.Value) any {
cancel()
return nil
}))
// 使用 context
go func() {
<-ctx.Done()
println("操作已取消")
}()
select {}
}
注意事项
限制
-
平台限制:
- 仅适用于 js/wasm 架构
- 需要 GOOS=js, GOARCH=wasm 编译
-
实验性:
- API 可能发生变化
- 不受 Go 兼容性承诺保护
-
事件循环:
- 包装的 Go 函数会阻塞 JavaScript 事件循环
- 异步操作需要特殊处理
-
资源管理:
- Func 必须调用 Release
- 忘记释放会导致内存泄漏
使用建议
-
编译命令:
GOOS=js GOARCH=wasm go build -o main.wasm main.go -
HTML 模板:
<!DOCTYPE html> <script src="wasm_exec.js"></script> <script> const go = new Go(); WebAssembly.instantiateStreaming( fetch("main.wasm"), go.importObject ).then(result => { go.run(result.instance); }); </script> -
避免的操作:
- 不要在包装函数中调用异步 JS API
- 不要长时间阻塞
- 不要忘记 Release
快速参考
类型映射表
| Go | JavaScript |
|---|---|
| js.Value | [its value] |
| js.Func | function |
| nil | null |
| bool | boolean |
| int/float | number |
| string | string |
| []interface{} | array |
| map[string]interface{} | object |
常用 JavaScript API
// Console
js.Global().Get("console").Call("log", "message")
// DOM
doc := js.Global().Get("document")
elem := doc.Call("getElementById", "id")
// 事件
elem.Call("addEventListener", "click", handler)
// 定时器
js.Global().Call("setTimeout", callback, 1000)
js.Global().Call("setInterval", callback, 1000)
// Fetch (需要 goroutine)
go func() {
promise := js.Global().Call("fetch", "/api")
// 处理 promise
}()
方法速查
| 方法 | 功能 |
|---|---|
Global() | 获取全局对象 |
ValueOf(x) | Go 值转 JS |
Get(p) | 获取属性 |
Set(p, x) | 设置属性 |
Call(m, args...) | 调用方法 |
Invoke(args...) | 调用函数 |
New(args...) | new 运算符 |
Index(i) | 获取索引 |
SetIndex(i, x) | 设置索引 |
Type() | 获取类型 |
Bool()/Int()/Float()/String() | 类型转换 |
总结
syscall/js 包提供了 Go 与 JavaScript 互操作的能力。
核心优势:
- ✅ 直接访问 WebAssembly 宿主环境
- ✅ 完整的 JavaScript API 访问
- ✅ Go 与 JS 双向通信
- ✅ 类型自动转换
重要限制:
- ⚠️ 仅适用于 js/wasm 架构
- ⚠️ 实验性 API,可能变化
- ⚠️ 需要手动管理资源
- ⚠️ 可能阻塞事件循环
主要用途:
- WebAssembly 模块开发
- 浏览器端 Go 代码
- JavaScript 库封装
- DOM 操作和事件处理
使用建议:
- 使用 GOOS=js GOARCH=wasm 编译
- 始终调用 Release 释放资源
- 避免在包装函数中阻塞
- 使用 goroutine 处理异步操作
- 检查类型避免 panic
编译示例:
GOOS=js GOARCH=wasm go build -o main.wasm main.go