You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 21:47:10