Cangjie/cangjie_js_interop 类型映射全解析:JSValue 与仓颉类型互转速查手册
【免费下载链接】cangjie_js_interop项目地址: https://gitcode.com/Cangjie/cangjie_js_interop
Cangjie/cangjie_js_interop(仓颉与 JavaScript 互操作库)为仓颉调用 JavaScript 提供了跨语言调用的完整能力,其中JSValue 类型映射与互转是所有跨语言数据流动的核心:JS 侧的number、string、object……到了仓颉侧,分别由谁承接、用什么方法转换、能存活多久?这篇全解析给出可直接对照的速查手册 📖。
git clone https://gitcode.com/Cangjie/cangjie_js_interop为什么类型映射是互操作的核心 🧭
仓颉调用 JavaScript 时,两边类型并不"长得一样":JS 侧的类型需要仓颉侧的"对应引用"来承接,跨语言传参和回调也依赖明确的对照关系。互操作库为此做了三件事:
- 为每种已支持的 JS 类型提供对应的仓颉引用类型;
- 提供统一的JSValue 类型映射体系做类型判断与转换;
- 按"弱引用 / 强引用"两类管理跨语言对象的生命周期。
理解这三层,基本就掌握了整库的使用逻辑。
完整类型映射表:一眼看懂对照关系
下表整理自官方用户手册,建议收藏对照使用(js_interop_user_manual.md):
| JS 类型 | 仓颉引用类型 | typeof类型 | 支持情况 |
|---|---|---|---|
| Undefined | JSUndefined | JSType.UNDEFINED | ✅ 已支持 |
| Null | JSNull | JSType.NULL | ✅ 已支持 |
| Boolean | JSBoolean | JSType.BOOLEAN | ✅ 已支持 |
| Number | JSNumber | JSType.NUMBER | ✅ 已支持 |
| String | JSString | JSType.STRING | ✅ 已支持 |
| Object | JSObject | JSType.OBJECT | ✅ 已支持 |
| Array | JSArray | JSType.OBJECT | ✅ 已支持 |
| Map | JSMap | JSType.OBJECT | ✅ 已支持 |
| Function | JSFunction | JSType.FUNCTION | ✅ 已支持 |
| Symbol | — | JSType.SYMBOL | ⏳ 暂不支持 |
| ArrayBuffer / Date / Set / Promise / RegExp / Class / BigInt | — | 对应JSType枚举 | ⏳ 暂不支持 |
💡 速记口诀:9 种已支持,"三小强"(String、Object 系、Function)可跨作用域,其余只在作用域内有效。
强引用还是弱引用:决定值的"寿命"⏳
同样是 JS 数据,引用方式不同,生命周期差别很大:
- 跨语言弱引用:
JSValue、JSUndefined、JSNull、JSBoolean、JSNumber——不阻止 JS 对象被回收,只在scope作用域内有效; - 跨语言强引用:
JSString、JSObject、JSArray、JSMap、JSFunction——统一继承自JSHeapObject做生命周期管理,可跨scope使用,在上下文存活期间有效。
⚠️ 实战要点:如果你要把值留给 JS 回调的仓颉函数(
JSLambda)稍后使用,请优先选择强引用类型,否则可能拿到已被回收的对象。
JSValue:互转枢纽的三族方法 🔑
JSValue是 JavaScript 统一类型在仓颉侧的弱引用表示,直接参与数据交互。它的实现位于 value.cj,方法可分为三族:
①is族 —— 判断类型(不转换)
isUndefined()、isNull()、isNullOrUndefined()、isBoolean()、isNumber()、isString()、isArray()、isObject()、isFunction()、isMap()、isSymbol()、isBigInt()、isPromise()、isExternal()
②as族 —— 转为引用类型
asUndefined()、asNull()、asBoolean()、asNumber()、asString()、asObject()、asArray()、asMap()、asFunction()
③to族 —— 取出仓颉原生类型
toBool()→Bool、toString()→String、toNumberFloat64()→Float64、toNumberInt32()→Int32、toNumberInt64()→Int64、toNumberUint32()→UInt32
另有typeOf()返回具体的JSVM_ValueType枚举。
互转方向速查表:JS → 仓颉 与 仓颉 → JS ⚡
JS → 仓颉(拿到 JS 值后按三步走:判断 → 取引用 → 取原生值):
| 场景 | 转换路径 |
|---|---|
| JS 数字 → 仓颉整数 | value.isNumber()→asNumber()→toNumberInt64() |
| JS 数字 → 仓颉浮点 | value.asNumber()→toNumberFloat64() |
| JS 字符串 → 仓颉字符串 | value.asString()→toString() |
| JS 布尔 → 仓颉布尔 | value.asBoolean()→toBool() |
| JS 数组 → 逐元素处理 | value.asArray()→array[i]继续判断 |
| JS 函数 → 直接调用 | value.asFunction()→globalCall([...]) |
仓颉 → JS(统一走JSContext工厂方法,详见 context.cj):
| 仓颉值 | 创建方法 | 得到的 JS 类型 |
|---|---|---|
Int32 / Int64 / UInt32 / Float64 | context.number(…) | Number |
String | context.string(…) | String |
Bool | context.boolean(…) | Boolean |
Array<ToJSValue> | context.array(…) | Array |
| 键值对集合 | context.object(…)/context.map(…) | Object / Map |
(JSContext, JSCallInfo) -> JSValue函数 | context.function(…) | Function |
| 特殊值 | context.undefined()/context.null() | Undefined / Null |
所有实现了ToJSValue接口的仓颉类型(包括JSValue本身)都能调用toJSValue(context)完成封装,写入JSObject/JSArray属性时会自动转换,非常顺手 ✨。
两个最常踩的坑 ⚠️
- 弱引用别跨作用域传:
JSValue等弱引用类型出newScope后可能失效,需要长期持有的数据先as成强引用类型; - 转换前先判断:
as/to族在类型不符时会抛异常,建议先用is族确认类型(或配合typeOf()排查),再执行转换。
延伸阅读与源码索引 📚
- 类型映射与生命周期规格:js_interop_user_manual.md
- 全部 API 参考:js_interop_api_docs.md
- 各类型映射实现源码:value.cj、array.cj、map.cj、object.cj、string.cj、function.cj
掌握这份 JSValue 与仓颉类型映射速查手册后,跨语言互转基本可以"查表即用"。祝开发顺利 🚀
【免费下载链接】cangjie_js_interop项目地址: https://gitcode.com/Cangjie/cangjie_js_interop
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考