☰
30 seconds of code 实战:如何将 HTML 表单转换为 JavaScript 对象
2026/10/4 7:22:05 网站建设 项目流程
  • 教程
  • 文档

【免费下载链接】30-seconds-of-code

Coding articles to level up your development skills

项目地址:https://gitcode.com/gh_mirrors/30/30-seconds-of-code
点击查看免费下载

HTML 表单是向用户收集输入的最基础、最推荐的方式,但真正把表单数据取回到 JavaScript 代码中,却常常让人绕弯路。本文以 30 seconds of code 仓库中的 form-to-object 技巧 为核心,讲解如何用FormData接口配合Object.fromEntries()一步得到普通对象,以及如何序列化成可直接拼接的查询字符串,并顺带覆盖编码边界、请求发送与相关扩展技巧。

核心思路:用 FormData 获取表单键值对

FormData接口提供了一种简洁的方式来构造一组代表表单字段及其值的键/值对(key/value pairs)。只要把表单元素的引用传给FormData()构造函数,浏览器就会自动扫描表单内所有带name属性的控件并收集它们的当前值:

const form = document.querySelector('#form'); const data = new FormData(form);

这一步完成之后,data就是一组可迭代的键值对,键是字段的name属性值,值是对应的输入内容。值得注意的是,它收集的是控件当前的实时值,而不是初始的value属性,因此非常适合在submit事件或input事件中动态读取。

将表单数据转换为普通对象:formToObject

拿到FormData对象后,只需再用Object.fromEntries()转换一次,就能得到字段名作为键、字段值作为值的普通 JavaScript 对象。这正是仓库文档给出的完整实现:

const formToObject = form => Object.fromEntries(new FormData(form)); formToObject(document.querySelector('#form')); // { email: 'test@email.com', name: 'Test Name' }

配合一个真实的表单来看,整个过程非常直观:

<form id="form"> <input type="text" name="name" value="Test Name" /> <input type="email" name="email" value="test@email.com" /> </form>
const formToObject = form => Object.fromEntries(new FormData(form)); formToObject(document.querySelector('#form')); // { email: 'test@email.com', name: 'Test Name' }

从实现原理看,Object.fromEntries()会把可迭代的键值对序列(iterable of key-value pairs)直接构造成对象,与Map、数组以及FormData都能自然衔接。仓库语言配置 content/languages/javascript.yaml 中把FormData、Object.fromEntries()等均登记为可检索的引用 API,足见这种组合是该技巧集合中的标准写法。

将表单数据序列化为查询字符串:serializeForm

如果需要的不是对象,而是把表单数据序列化(serialize)成查询字符串,只需要对前面的代码做几处调整。创建FormData对象后,用Array.from()得到条目数组,再利用其第二个参数指定每条条目如何映射:把键与值用=连接,并对每一部分应用encodeURIComponent()。最后用Array.prototype.join()以&作为分隔符拼接成查询字符串:

const serializeForm = form => Array.from(new FormData(form), field => field.map(encodeURIComponent).join('=') ).join('&'); serializeForm(document.querySelector('#form')); // 'email=test%40email.com&name=Test%20Name'

为什么每个部分都要 encodeURIComponent

encodeURIComponent()会转义字符串中除A-Z a-z 0-9 - _ . ! ~ * ' ( )之外的所有字符。对于表单值这种只作为 URL 一部分的字符串,它是正确的选择。仓库的姊妹篇 encodeuri-encodeuricomponent.md 明确对比过两者的区别:

  • encodeURIComponent():适合编码 URL 的片段,会转义@、空格、&、=等保留字符,这正是查询参数所需的;
  • encodeURI():适合编码完整 URL,会保留? : / @ & =等 URL 结构字符,若用它编码参数值会导致查询串结构被破坏。

因此示例输出中,test@email.com变成test%40email.com,Test Name中的空格变成%20——这正是标准的application/x-www-form-urlencoded编码方式,可直接用于 GET 请求或拼接到 URL 上。

实战:把表单数据用于请求与发送

两种函数各自适合不同的场景,综合使用可以覆盖从"本地拿到数据"到"发送给服务端"的完整链路:

// 场景一:读取表单值到对象,供前端逻辑使用(如表单预填、校验) const obj = formToObject(document.querySelector('#form')); // 场景二:把表单拼成查询字符串,追加到 URL 发起 GET 请求 const qs = serializeForm(document.querySelector('#form')); fetch(`/api/search?${qs}`);

而在需要发送multipart/form-data(如同时携带文件上传)的场景,FormData对象本身可以直接作为fetch()的 body,浏览器会自动设置正确的Content-Type与边界:

document.querySelector('#form').addEventListener('submit', e => { e.preventDefault(); fetch('/api/upload', { method: 'POST', body: new FormData(e.target), }); });

边界情况与注意事项

理解FormData的收集规则,可以避免踩坑:

  • 必须有name属性:没有name的控件不会出现在结果中;
  • 禁用控件被忽略:disabled的输入框、下拉框不会被收集;
  • 未选中的复选框:不会被收集;选中的复选框才会以它的value(缺省为"on")出现;
  • 重复的name:同名的多个控件(如多选下拉框、同名 checkbox 组)会生成多个键值对,Object.fromEntries()只保留最后一个,而serializeForm的映射会全部保留;
  • 空值与空串:空输入框会以空字符串值出现,序列化时会编码为key=;
  • 文件输入:FormData中对应条目的值是File对象,直接转成普通对象或字符串会丢失文件内容,这类场景应保留FormData形态发送。

相关技巧延伸:查询字符串与对象互转

表单序列化得到的查询字符串,日后还需要解析回来。仓库中的 query-string-to-object.md 给出了对应的逆向操作:用String.prototype.split()切出?之后的部分,交给URLSearchParams()构造器,再用展开运算符与Object.fromEntries()还原成对象:

const queryStringToObject = url => Object.fromEntries([...new URLSearchParams(url.split('?')[1])]); queryStringToObject('https://google.com?page=1&count=10'); // {page: '1', count: '10'}

反向的objectToQueryString则用Object.entries()配合Array.prototype.reduce()拼接,只在字符串非空时追加?,后续键值对用&连接:

const objectToQueryString = queryParameters => { return queryParameters ? Object.entries(queryParameters).reduce( (queryString, [key, val], index) => { const symbol = queryString.length === 0 ? '?' : '&'; queryString += typeof val === 'string' ? `${symbol}${key}=${val}` : ''; return queryString; }, '' ) : ''; }; objectToQueryString({ page: '1', size: '2kg', key: undefined }); // '?page=1&size=2kg'

它与serializeForm相互呼应:一个负责"对象 → 查询字符串",一个负责"表单 → 查询字符串",再加上queryStringToObject的"字符串 → 对象",三者在实际项目中经常配合使用。

在仓库中的定位与继续学习

本文讲解的两种技巧位于仓库的 form-to-object.md,带有browser与object两个标签。它既属于 browser 浏览器技巧集合(该集合专注于 DOM 元素的选取、遍历与操作),也属于 object 对象技巧集合。如果想继续深入,仓库中还有大量相关姊妹篇可以对照阅读:

  • encodeuri-encodeuricomponent.md:URL 编码的两个函数如何选择;
  • query-string-to-object.md:查询字符串与对象互转;
  • edit-url-params.md 与 construct-url.md:URL 参数的读取与改写。

掌握formToObject与serializeForm两个工具函数,就掌握了从"用户填写的表单"到"JavaScript 可操作的数据结构"之间最轻量的两条通路,足以覆盖绝大多数前端表单处理的日常需求。

  • 教程
  • 文档

【免费下载链接】30-seconds-of-code

Coding articles to level up your development skills

项目地址:https://gitcode.com/gh_mirrors/30/30-seconds-of-code
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询