在Go中通过syscall/js定义JavaScript类的实现是否合理可行?
方案合理性结论
你当前的实现是合理且可靠的,完全符合JavaScript类的底层运行逻辑,你观察到的和原生class的差异仅为调试展示层面的差异,不会影响实例化、方法调用、类继承等正常功能的使用。
差异来源说明
你看到的两类差异都是Go syscall/js包的底层固有实现导致的,和你的实现逻辑无关:
- 所有通过
js.FuncOf()创建并暴露到JS环境的函数,都会被Go runtime底层的_makeFuncWrapper包装,默认不会同步Go侧定义的函数名、参数长度信息,所以会出现name为空、length为0的情况 - 原生JS的
class是ES6新增的语法糖,浏览器控制台会对其做特殊的样式标识,而你通过「构造函数+原型挂载」的实现是ES5时代的标准类实现方式,所以控制台会显示为普通函数形式,运行层面和原生class没有本质区别
可选优化方案
如果需要缩小和原生class的显示差异,可以通过JS内置的Object.defineProperty手动补全属性,参考修改后的main函数逻辑:
func main() { const name = "Rectangle" const paramCount = 2 rectangle := js.FuncOf(rectangleConstructor) rectangle.Set("prototype", map[string]interface{}{ "constructor": rectangle, "area": js.FuncOf(rectangleArea), }) // 补全name属性 js.Global().Get("Object").Call("defineProperty", rectangle, "name", map[string]interface{}{ "value": name, "configurable": true, }) // 补全length属性 js.Global().Get("Object").Call("defineProperty", rectangle, "length", map[string]interface{}{ "value": paramCount, "configurable": true, }) js.Global().Set(name, rectangle) select {} }
优化后你再在控制台打印Rectangle,就会和原生class的显示信息基本一致。
注意事项
- 你代码中创建的
js.Func因为是全局注册的类,整个Wasm实例生命周期内都需要调用,所以不需要手动调用Release()释放资源,没有内存泄漏风险 - 如果后续需要实现更复杂的类特性(比如私有属性、静态方法),可以按照JS的底层逻辑对应实现即可:静态方法直接挂载到构造函数对象上,私有属性可以用WeakMap或者Symbol实现,逻辑和原生JS的ES5类实现完全一致
内容的提问来源于stack exchange,提问作者Alexander Klauer
相关产品推荐
相关产品推荐

