history.pushState 和 replaceState 的核心区别在于:pushState 在历史栈新增记录,replaceState 仅替换当前条目;前者支持返回上一页,后者不改变后退路径。

history.pushState 和 history.replaceState 的核心区别
两者都用来修改浏览器地址栏,但 pushState 会在历史栈中新增一条记录,而 replaceState 只替换当前条目,不增加新记录。这意味着调用 replaceState 后按浏览器「后退」按钮不会回到上一个 URL,而是继续回退到更早的页面。
-
pushState适合页面内导航(如切换 Tab、翻页),用户希望保留返回路径 -
replaceState适合修正当前 URL(如去掉 hash、补全 query 参数),不希望干扰用户历史行为 - 两个方法第三个参数
title在多数浏览器中被忽略,可传空字符串或null - 第一个参数
state必须是可序列化的对象,不能是函数或 DOM 节点,否则会抛DataCloneError
监听 popstate 事件捕获回退/前进操作
浏览器点击后退/前进按钮,或调用 history.back()、history.forward() 时,会触发 popstate 事件。注意:仅当历史记录由 pushState 或 replaceState 创建(或初始页面加载)才会触发,直接跳转普通链接不会触发。
- 事件对象的
state属性就是当时传入pushState或replaceState的第一个参数 - 必须用
addEventListener('popstate', handler)注册,不能用onpopstate(部分浏览器不支持) - 首次页面加载时,Chrome/Firefox 不会触发
popstate,Safari 会——需要手动检查history.state做兼容
window.addEventListener('popstate', (event) => {
const state = event.state;
if (state && state.page === 'list') {
renderList(state.query);
}
});
history.go()、back()、forward() 的实际行为差异
这三个方法都依赖浏览器历史栈,但控制粒度不同。它们不会触发 popstate 事件(只有用户操作或 go() 引起的跳转才触发),且无法跨域跳转(遇到跨域记录会静默失败)。
-
history.back()等价于history.go(-1),但语义更清晰 -
history.go(0)是刷新当前页,但不会重新发送 POST 请求(类似 F5 的行为) - 调用
history.go(n)时若目标超出历史栈范围(如go(100)),浏览器静默忽略,不报错也不跳转 - 在 iframe 中调用这些方法只影响该 iframe 的历史,不影响父页面
常见错误:URL 路径不合法导致 pushState 失败
pushState 和 replaceState 的第二个参数(URL)必须与当前页面同源,否则抛 SecurityError。即使只是相对路径,也受当前 document.URL 影响;如果当前是 file:// 协议,几乎所有操作都会失败。










