Tally:表单该问什么,由刚才的回答决定
Tally让人像写文档一样创建并分享在线表单。条件逻辑可以根据回答调整问题、必填项与后续页面,让报名、需求收集和反馈流程只询问相关信息。
先尝试拆解问题、设计和实现,再展开思路,检查状态、边界与取舍,并设计验证用例。思路提供分析路径,不给出完整实现。
隐藏的草稿,应该怎样参与条件表单计算?
练习场景
在 JS 前端中设计一个纯函数,把表单定义和本地草稿转换成“当前可见字段、缺失项、待提交数据”。待提交数据只包含当前分支的有效答案;本地草稿保持不变,可以保留隐藏答案供切回时恢复。函数不修改草稿、不操作DOM、不发送请求。协议是本题自拟,不是 Tally 的实际实现。
输入合同
- fields 为最多 10,000 项的有序数组,每项是非 null 对象:唯一非空字符串 id、布尔值 required,以及可选 when。缺省 when 表示一直可见;显式 null 非法。其他字段忽略。
- when 是非 null 对象,含 mode 为 all 或 any,以及 1–20 项 terms。每个 term 含非空字符串 fieldId 和非空字符串 equals。fieldId 必须指向 fields 中严格位于当前字段之前的字段;不存在、向后引用和自引用均非法。重复 term 允许且不改变布尔含义。所有 term 总数为 m。
- draft 是 JS Map,键和值都必须是字符串;键必须对应已定义字段。值允许空字符串,空字符串表示未回答,不执行 trim,空格按普通字符处理。对可见字段,非空草稿值即有效答案;隐藏字段即使有缓存值,也没有有效答案。
- term 只有在引用字段可见、具有有效答案且答案与 equals 严格相等时才成立。all 要全部成立;any 要至少一个成立。未回答与隐藏均不能命中。没有嵌套条件树,也不允许条件修改答案。
- 完整校验所有字段、条件与草稿,即使某分支最后隐藏也不能跳过非法规则。任何错误返回位置并拒绝整批,不输出部分结果。合法输入返回三类列表,均按 fields 中的顺序排列:visibleIds 包含全部当前可见字段;missingRequiredIds 包含可见、必填且没有有效答案的字段;submissionEntries 只包含可见且有有效答案的 [id,value] 对。即使缺少必填也返回这些结果,但 canSubmit 必须为 false。
- 空 fields 与空 draft 合法,输出空列表且 canSubmit=true。所有ID、条件常量和草稿值的总字符长度为 L。不要把任意用户ID写到普通对象原型上;输出使用条目数组或安全容器。
小例子
字段依次为 mode(一直可见、必填)、address(mode等于online时可见、必填)、invoice(mode等于online时可见、选填)、taxId(invoice等于yes时可见、必填)。每个条件只含一个term。草稿是 mode=offline、address=某测试地址、invoice=yes、taxId=空字符串。
写出四个输出。然后把 mode 改成 online 再算一次;最后把 invoice 改成 no 再算一次。特别解释 mode=offline 时,缓存 invoice=yes 为什么不能让 taxId 出现。
另外检查:(a) taxId改为引用未来字段;(b) 草稿中含未知字段;(c) 任意一个条件字段等于__proto__,但该ID已合法定义且位于前面;(d) all含一真一假与any含一真一假。
交付物
描述先校验、再按定义顺序求可见性与有效答案、最后组装输出的方案。说明为何不能直接把draft整体提交,也不能只检查DOM隐藏状态。分析 n 个字段、m 个条件与 L 的时间空间,列出至少四个不变量,不给完整代码或逐行伪代码。
查看思路
- 先验证整个定义与草稿。 用Map记录字段下标,检查重复ID、类型、条件长度、引用位置和草稿键值。条件只能引用前面的字段,因此按给定顺序计算一遍即可,无需重复计算到结果稳定。不能因为当前隐藏就容忍未知引用。
- 按字段顺序建立有效答案。 先计算when,再决定是否从草稿取非空值。条件读取的是已计算的有效答案,不是原始缓存,因此隐藏invoice的yes不会激活taxId。all/any只影响如何组合,不能改变缺失答案的规则。
- 把三类输出分开。 可见字段进入visibleIds;可见、必填且无有效答案者进入missingRequiredIds;可见且有值者进入submissionEntries。canSubmit仅由缺失列表是否为空决定,原草稿始终不变。
- 手推返回路径。 offline时只有mode可见,缺失为空,提交只有mode=offline,可提交。改online后四字段均可见,taxId缺失,提交mode/address/invoice三项,不可提交。再改invoice=no后taxId隐藏,前三字段可见且有值,无缺失,可提交。草稿缓存从未被函数删除。
- 检查边界与成本。 未来引用和未知草稿键整批失败;合法__proto__按普通字符串ID处理;一真一假在all下假、any下真。隐藏字段不进入提交也不驱动后续,输入不变、输出顺序稳定、错误无部分结果。平均Map操作下O(n+m)次结构操作,字符串比较/哈希成本按L另计;如同一长答案被多个term反复比较,还要计入实际重复比较字符量,不能只以唯一字符串长度声称线性。额外空间O(n+m+L)可覆盖校验索引和输出。