先记住这个答案
new FormData(form) 根据 HTML 表单的成功控件规则生成数据项。它不仅看 <form> 标签里的节点,也看真正归属该表单的外部控件;同时跳过禁用输入、没有适用名称的控件以及未勾选的复选框。同名字段可以产生多个值,因此读取全部值时用 getAll() 而不是只用 get()。
- 收集依据是表单归属与成功控件规则
- 禁用控件不会进入数据
- 未勾选复选框通常没有数据项
- 同名字段可产生多个值
哪些控件会出现
做筛选表单时,两个同名复选框都勾选了,就会生成两条同名数据。没有勾选的复选框不会生成 false 字符串。文件输入可能生成文件对象,不能把所有数据项都假设成纯文本。表单外的控件若用 form 关联也可能进入结果。
<form id="filters">
<label><input type="checkbox" name="tag" value="js" checked>JS</label>
<label><input type="checkbox" name="tag" value="css" checked>CSS</label>
<input name="internal" value="skip" disabled>
</form>以此构造数据时,getAll("tag") 可得到两个标签值;internal 因禁用而不出现。若业务需要明确发送“未选中”,应由应用构造相应字段,不能指望普通复选框自动产生 false。
构造数据不等于提交表单
new FormData(form) 只在内存里构造数据,不会自动导航或发请求。随后可以交给 fetch,也可以追加字段。若要模拟某个提交按钮的名称和值,可使用支持提交者参数的构造形式,传入目标按钮。
它也不应被当成绕过服务端验证的工具。用户可自行构造 HTTP 请求;服务端仍需校验每个字段。用 FormData 发送文件时,让浏览器设置带边界的 Content-Type,不要只手写一个没有 boundary 的 multipart 类型。
调试时可以在控制台运行 Array.from(new FormData(form).entries()),直接看到发送前有哪些键值对;同名复选框会出现多次。还要区分“是否在表单里”和“是否属于表单”:控件可以通过 form 属性归属到外部表单,反过来即使视觉上在表单内部,也可能归属别的表单。文件输入的值是 File 对象,不是文件路径字符串。一个未选择文件的文件输入也有特定的空文件提交规则,不能用 input.value 判断整份表单是否包含文件数据。
容易答错的地方
- 认为表单内所有输入都会出现
- 禁用、未勾选、无
name等情况会缺席;表单外关联控件也可能出现。 - 用
get()读取所有同名复选框 get()只取一项;要读取多个同名值应使用getAll()。
面试官还会怎么问?
提交按钮本身会被默认收集吗?
只传 form 构造时通常没有具体提交者;需要该按钮值时可使用带提交者的构造方式。
未勾选复选框会得到 false 吗?
不会,普通表单数据中通常没有这个字段项。
创建 FormData 会触发校验吗?
构造数据不等于执行原生提交;是否调用校验取决于具体流程。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。