网站首页 > 技术文章 正文
大家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
1.什么是 goja
Goja 是 ECMAScript 5.1 的纯 Go 实现,强调标准合规性和性能,项目很大程度上受到 otto 的启发,而 otto 包是一个用 Go 原生编写的 JavaScript 解析器和解释器。Goja 所需的最低 Go 版本是 1.16。
ECMAScript/JavaScript engine in pure Go
Goja 的典型特征包括:
- 完整的 ECMAScript 5.1 支持(包括正则表达式和严格模式)。
- 通过了迄今为止实现的功能的几乎所有 tc39 测试。
- 能够运行 Babel、Typescript 编译器和几乎任何用 ES5 编写的东西。
- 支持 Sourcemaps
- 大多数 ES6 功能仍在进行中,可以参阅 https://github.com/dop251/goja/milestone/1?close=1
目前 Goja 在 Github 上通过 MIT 协议开源,有超过 4.7k 的 star,7.2k 的项目依赖量,是一个值得关注的前端开源项目。
2.goja 基本用法
运行 JavaScript 并获取结果值
vm := goja.New()
v, err := vm.RunString("2 + 2")
if err != nil {
panic(err)
}
if num := v.Export().(int64); num != 4 {
panic(num)
}
从 JS 导出值
可以使用 Value.Export() 方法将 JS 值导出为其默认的 Go 表示形式。或者,可以使用 Runtime.ExportTo() 方法将其导出到特定的 Go 变量中。
var fn func(string) string
err = vm.ExportTo(vm.Get("f"), &fn)
if err != nil {
panic(err)
}
在单个导出操作中,相同的对象将由相同的 Go 值(相同的映射、切片或指向相同结构的指针)表示,这包括 circular objects 并使得导出它们成为可能。
从 Go 调用 JS 函数
有两种方法,第一种方法是使用 AssertFunction():
const SCRIPT = `
function sum(a, b) {
return +a + b;
}
`
vm := goja.New()
_, err := vm.RunString(SCRIPT)
if err != nil {
panic(err)
}
sum, ok := goja.AssertFunction(vm.Get("sum"))
if !ok {
panic("Not a function")
}
res, err := sum(goja.Undefined(), vm.ToValue(40), vm.ToValue(2))
if err != nil {
panic(err)
}
fmt.Println(res)
// Output: 42
当然,还可以使用 Runtime.ExportTo():
const SCRIPT = `
function sum(a, b) {
return +a + b;
}
`
vm := goja.New()
_, err := vm.RunString(SCRIPT)
if err != nil {
panic(err)
}
var sum func(int, int) int
err = vm.ExportTo(vm.Get("sum"), &sum)
if err != nil {
panic(err)
}
fmt.Println(sum(40, 2))
// note, _this_ value in the function will be undefined.
// Output: 42
第一个函数的更加偏底层,允许指定该值,而第二个函数使该函数看起来像普通的 Go 函数。
3.goja 已知不兼容性和警告
WeakMap
WeakMap 是通过将对值的引用嵌入到键中来实现的, 这意味着只要键是可访问的,任何 WeakMap 中与其关联的所有值也仍然是可访问的,因此即使没有以其他方式引用,或者即使在 WeakMap 消失之后也无法进行垃圾收集。 当从 WeakMap 中显式删除该键或该键变得无法访问时,对该值的引用将被删除。
var m = new WeakMap();
var key = {};
var value = {/* 很大的对象 */};
m.set(key, value);
value = undefined;
m = undefined;
// 此时该值不会变成可垃圾回收的
key = undefined;
// 可以回收
// m.delete(key);
// 也可以垃圾回收
其原因是 Go 运行时的限制。 在撰写本文时(版本 1.15),在作为引用循环一部分的对象上设置终结器会使整个循环不可垃圾收集。 上面的解决方案是我能想到的唯一合理的方法,而不涉及终结器。
请注意,这不会对应用程序逻辑产生任何影响,但可能会导致内存使用量高于预期。
WeakRef 和 FinalizationRegistry
由于上述原因,现阶段实现 WeakRef 和 FinalizationRegistry 似乎是不可能的。
JSON
JSON.parse() 使用以 UTF-8 运行的标准 Go 库。因此,无法正确解析损坏的 UTF-16 代理项对,例如:
JSON.parse(`"\\uD800"`).charCodeAt(0).toString(16)
// 返回 "fffd" 而不是 "d800"
Date
从日历日期(calendar date )到纪元时间戳(epoch timestamp )的转换使用标准 Go 库,该库使用 int,而不是按照 ECMAScript 规范使用 float。 这意味着,如果将溢出 int 的参数传递给 Date() 构造函数,或者存在整数溢出,则结果将不正确,例如:
Date.UTC(1970, 0, 1, 80063993375, 29, 1, -288230376151711740) // returns 29256 instead of 29312
4.本文总结
本文主要和大家介绍 Goja,其是 ECMAScript 5.1 的纯 Go 实现,强调标准合规性和性能,项目很大程度上受到 otto 的启发,而 otto 包是一个用 Go 原生编写的 JavaScript 解析器和解释器。关于 Goja 只是做了一个简短的介绍,但是文末的参考资料提供了大量优秀文档以供学习,如果有兴趣可以自行阅读。如果大家有什么疑问欢迎在评论区留言。
参考资料
https://github.com/dop251/goja
https://pkg.go.dev/github.com/dop251/goja#section-readme
https://github.com/robertkrimen/otto
https://morioh.com/a/08a5a7879bbf/goja-ecmascriptjavascript-engine-in-pure-go
https://www.linkedin.com/pulse/otto-gem-js-library-umakanthan-diwakaran
https://www.linkedin.com/pulse/otto-gem-js-library-umakanthan-diwakaran
猜你喜欢
- 2024-12-18 比较 JavaScript 对象的四种方式「实践」
- 2024-12-18 我不知道还可以用 JS 做的 6 件事
- 2024-12-18 什么是 JavaScript? 什么是首发经济
- 2024-12-18 10 个常问的 JS 面试题 js面试题库
- 2024-12-18 理解 Next.js 中的 CSR、SSR、SSG、ISR 以及 Streaming
- 2024-12-18 JS 图片简易压缩【实践】 js压缩图片到指定大小
- 2024-12-18 技术分享 | 想做App测试就一定要了解的App结构
- 2024-12-18 好程序员web前端教程分享web前端都学些什么
- 2024-12-18 要深入 JavaScript,你需要掌握这 36 个概念
- 2024-12-18 帮你彻底搞懂 JS 中的 prototype、__proto__与constructor
你 发表评论:
欢迎- 最近发表
-
- 前端流行框架Vue3教程:13. 组件传递数据_Props
- 前端必看!10 个 Vue3 救命技巧,解决你 90% 的开发难题?
- JAVA和JavaScript到底是什么关系?是亲戚吗?
- Java和js有什么区别?(java和javascript的区别和联系)
- 东方标准|Web和Java的区别,如何选择这两个专业
- 前端面试题-JS 中如何实现大对象深度对比
- 360前端一面~面试题解析(360前端笔试)
- 加班秃头别慌!1 道 Vue 面试题,快速解锁大厂 offer 通关密码
- 焦虑深夜刷题!5 道高频 React 面试题,吃透 offer 稳了
- 2025Web前端面试题大全(整理版)面试题附答案详解,最全面详细
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端md5加密 (49)
- 前端路由 (55)
- 前端数组 (65)
- 前端定时器 (47)
- 前端懒加载 (45)
- 前端接口 (46)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle查询数据库 (45)
- oracle约束 (46)
- oracle 中文 (51)
- oracle链接 (47)
- oracle的函数 (57)
- mac oracle (47)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)