先记住这个答案
写在 HTML 标记里的 value 是输入框的初始值,用户输入时变化的是 DOM value 属性。因而 getAttribute("value") 可能仍返回旧值,表单提交和即时校验应读取当前属性。需要重置表单或比较“是否改过”时,再看 defaultValue 与当前值的关系。
input.value是当前输入值getAttribute读初始内容属性defaultValue与重置有关- 复选框是否选中看
checked
用户改名后为什么仍提交旧值
服务端渲染了 <input value="张三">。用户把它改成“李四”,提交按钮却用 getAttribute("value") 收集数据,仍发出“张三”。改为读取 input.value 才得到“李四”。这个差异在表单重置时也能观察:reset() 会把当前值恢复到默认值,默认值又与初始属性相关。框架的受控输入还有自己的状态同步规则,但底层 DOM 区别一样重要。
<input id="name" value="张三">
<script>
const input = document.querySelector("#name")
input.value = "李四" // 当前值变化
console.log(input.value) // 李四
console.log(input.getAttribute("value")) // 张三
</script>HTML 内容属性来自标记,DOM 属性是运行时对象上的值。
示例中脚本把当前值改成“李四”后,输入框显示和提交值都应按当前值走;getAttribute("value") 留在“张三”,恰好可用来说明属性不是实时镜像。若再把内容属性改成“王五”,浏览器对当前值的同步还受用户是否已修改输入状态影响。面试回答只需先抓住初始值与当前值的区分,不要把所有属性都当成永远一一同步。
当前值与默认值会分离
对文本输入框,当前值与默认值在用户编辑后可以分离;defaultValue 对应默认值来源。设置 input.value 改变当前值,不等于改写原始 value 内容属性。不同表单控件的属性反射细节不完全相同,例如复选框更常关心当前 checked 与默认 defaultChecked,所以不要把所有 attribute/property 都套成同一种规则。
例如标记是 <input value="旧名">,用户把它改成“新名”后,input.value 是新名,getAttribute("value") 仍可能是旧名。form.reset() 又会把当前值恢复到默认值。框架重新渲染时若不断把旧标记值写回 DOM,就会出现输入被覆盖的体验;排查时要分清浏览器当前值、HTML 默认值和框架保存的状态。
这个区别也适用于复选框的 checked:标记上的 checked 表示默认选中,用户当前是否勾选看 DOM 的 checked 属性。调试表单时如果统一用 getAttribute() 读状态,输入框值和选中状态都可能拿到初始化信息而非当前操作结果。只有确实要恢复默认或比较修改前后时,才去读对应的默认状态。
容易答错的地方
- 认为 attribute 和 property 始终同步
- 有些属性会反射,但输入框当前值编辑后可与初始内容属性分离。
- 用
getAttribute("value")做提交校验 - 它可能拿到旧的默认值,当前输入应从
input.value读取。
面试官还会怎么问?
defaultValue 是什么?
它表示输入框的默认值,与 value 内容属性相关,表单重置时会作为恢复目标。
复选框也读 value 判断是否勾选吗?
不行。是否勾选看当前 checked,value 是被选中时提交的值。
框架受控输入会改变这个区别吗?
框架会同步状态到 DOM,但当前值与初始内容属性的区别仍存在。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。