如何将含getter的JavaScript对象转换为Lua表用于维基模块?
将含Getter的JavaScript对象转换为Lua表的方案
问题说明
需要把包含getter属性的JavaScript对象完整转换成Lua表用于维基模块,目前普通键值对已转换完成,但getter部分无法正确处理。
原JavaScript对象代码
var obj = { 'acad': { mL:50, w:[64,68,115,263,382,626], g:[0,0,0,0,225,428,744], mS:[0,8,12,16,22,28,35], tm:{a:1440,b:1,c:1.2,d:720,e:[984]}, get d(){ var t=[],c=this.tm; for(var i=0;i<this.mL;i++){ var d=Math.round(c.a/c.b*Math.pow(c.c,i+1)-c.d) - (c.e!=undefined?(c.e[i]!=undefined?c.e[i]:0):0); t.push((d>1728e3?1728e3:d)); } return t; } } }
未完成转换的Lua表代码(getter部分错误)
local obj = { ["acad"] = { ["mL"] = 50, ["w"] = {64,68,115,263,382,626}, ["g"] = {0,0,0,0,225,428,744}, ["mS"] = {0,8,12,16,22,28,35}, ["tm"] = { ["a"] = 1440, ["b"] = 1, ["c"] = 1.2, ["d"] = 720, ["e"] = {984} }, -- 此处为错误的JS语法,Lua不支持这种getter写法 get d(){var t=[],c=this.tm;for(var i=0;i<this.mL;i++){var d=Math.round(c.a/c.b*Math.pow(c.c,i+1)-c.d)-(c.e!=undefined?(c.e[i]!=undefined?c.e[i]:0):0);t.push((d>1728e3?1728e3:d));}return t;} } }
解决思路与实现
Lua没有JavaScript原生的getter语法,需要通过函数封装或元表模拟两种方式实现等价逻辑:
方式一:函数封装(简单直接)
将JS的getter逻辑翻译成Lua函数,作为表的一个字段,调用时执行计算并返回结果:
local obj = { ["acad"] = { ["mL"] = 50, ["w"] = {64,68,115,263,382,626}, ["g"] = {0,0,0,0,225,428,744}, ["mS"] = {0,8,12,16,22,28,35}, ["tm"] = { ["a"] = 1440, ["b"] = 1, ["c"] = 1.2, ["d"] = 720, ["e"] = {984} }, ["d"] = function(self) local t = {} local c = self.tm local mL = self.mL -- Lua 5.1无原生round函数,自行实现 local function round(x) return math.floor(x + 0.5) end local max_val = 1728 * 1000 -- 对应JS的1728e3 for i = 0, mL - 1 do -- 核心计算逻辑 local calc_val = round(c.a / c.b * math.pow(c.c, i + 1) - c.d) -- 处理e数组的取值(注意JS与Lua数组索引差异) local e_val = c.e and (c.e[i + 1] or 0) or 0 local d_val = calc_val - e_val -- 限制最大值 table.insert(t, d_val > max_val and max_val or d_val) end return t end } } -- 使用示例:调用函数获取d的值 local d_result = obj.acad:d()
方式二:元表模拟getter(贴近JS体验)
通过Lua的元表__index方法,实现访问d属性时自动执行计算逻辑,无需显式调用函数:
-- 先定义基础表 local acad_base = { ["mL"] = 50, ["w"] = {64,68,115,263,382,626}, ["g"] = {0,0,0,0,225,428,744}, ["mS"] = {0,8,12,16,22,28,35}, ["tm"] = { ["a"] = 1440, ["b"] = 1, ["c"] = 1.2, ["d"] = 720, ["e"] = {984} } } -- 定义元表,实现getter逻辑 local acad_mt = { __index = function(t, key) if key == "d" then local c = t.tm local mL = t.mL local function round(x) return math.floor(x + 0.5) end local max_val = 1728 * 1000 local result = {} for i = 0, mL - 1 do local calc_val = round(c.a / c.b * math.pow(c.c, i + 1) - c.d) local e_val = c.e and (c.e[i + 1] or 0) or 0 local d_val = calc_val - e_val table.insert(result, d_val > max_val and max_val or d_val) end return result end -- 其他属性直接返回原始值 return rawget(t, key) end } -- 为基础表设置元表 setmetatable(acad_base, acad_mt) -- 组装最终对象 local obj = { ["acad"] = acad_base } -- 使用示例:直接访问属性获取d的值 local d_result = obj.acad.d
两种方式对比
- 函数封装:代码简洁,无需额外元表操作,适合简单场景;缺点是需要显式调用函数。
- 元表模拟:访问方式更贴近JavaScript的getter体验,无需手动调用函数;缺点是需要额外设置元表,逻辑稍复杂。
内容的提问来源于stack exchange,提问作者Panos
相关产品推荐
相关产品推荐

