Goja实现类setTimeout函数时遇可变参数展开异常问题
问题分析
你遇到的核心问题是goja对Go可变参数函数与JS函数的绑定逻辑导致的:当你将JS箭头函数作为参数传给Go侧定义的func(int, int, ...int)类型函数时,goja会把额外的参数(3、4)打包成一个slice传递给Go函数的可变参数部分,而不是将它们展开为单独的参数。当Go侧调用这个函数时,JS箭头函数的第三个参数会接收到这个slice,第四个参数自然未被赋值。
解决方案
不要将JS函数断言为Go的可变参数函数类型,而是直接通过goja的Callable接口调用JS函数,手动传递所有单独的参数:
package main import ( "github.com/dop251/goja" ) func main() { vm := goja.New() err := vm.Set("myFunc", func(call goja.FunctionCall) goja.Value { // 取出传入的JS函数 jsFunc, ok := call.Argument(0).(goja.Callable) if !ok { panic("expected a function") } // 准备要传递的所有参数,逐个转为goja.Value args := []goja.Value{ vm.ToValue(1), vm.ToValue(2), vm.ToValue(3), vm.ToValue(4), } // 调用JS函数,传入所有参数 result, callErr := jsFunc.Call(goja.Undefined(), args...) if callErr != nil { panic(callErr) } return result }) if err != nil { panic(err) } jsCode := ` myFunc((a, b, c, d) => { console.log(a, b, c, d); // 现在会输出:1 2 3 4 }); ` _, runErr := vm.RunString(jsCode) if runErr != nil { panic(runErr) } }
原理说明
goja对Go函数的参数绑定规则是:
- 对于Go的可变参数(
...T),JS传入的多个参数会被自动打包成[]T类型的slice - 如果你希望JS函数接收单独的离散参数,必须直接通过
goja.Callable的Call方法传递参数,该方法支持可变参数展开,会将每个元素作为单独的参数传递给JS函数
内容的提问来源于stack exchange,提问作者Tim Macphail
相关产品推荐
相关产品推荐

