打开浏览器控制台,随手抓一个页面的a标签,用 `document.querySelector('a')` 拿到元素,然后访问它的 `href` 属性——你会得到两种截然不同的结果。这取决于你写的是 `a.href` 还是 `a.getAttribute('href')`。
我见过太多人在这个问题上翻车。去年帮同事排查一个爬虫脚本的bug,他死活拿不到相对路径,打印出来永远是带域名的绝对URL。折腾了半小时才发现,他一直用的是 `.href` 而不是 `getAttribute`。
HTML里写的是这样:
<a id="link" href="/article/123">文章</a> 在JavaScript里做这个操作:
const a = document.getElementById('link'); console.log(a.href); // "https://example.com/article/123" console.log(a.getAttribute('href')); // "/article/123" `.href` 返回的是经过浏览器解析后的绝对地址。浏览器拿到HTML那一刻,就把相对路径、协议、域名拼好了。`getAttribute('href')` 拿到的才是你在源码里写的那个原始字符串。
这不是什么冷知识,但实际开发中踩坑的人一茬接一茬。原因很简单:大多数教程只告诉你“用.href获取链接”,没讲清楚它和getAttribute的区别。
如果你要做页面跳转判断,比如检测当前链接是否指向站外,`.href` 更省事。直接拿到的就是完整URL,不用自己拼域名。
const isExternal = (a) => { return a.href.startsWith('http') && !a.href.includes(location.hostname); }; 但如果你要处理的是原始数据——比如把链接存进数据库、传给后端API、或者做链接替换——那就得用 `getAttribute('href')`。否则你存进去的全是带域名的绝对路径,换一个环境(比如从测试服切到生产服)就全废了。
还有一种情况:`href` 可能压根不存在。比如用JavaScript绑定点击事件的假链接:
<a id="btn" onclick="doSomething()">点我</a> 这时候 `a.href` 返回空字符串,`a.getAttribute('href')` 返回 `null`。判断的时候得留个心眼。
有些href值浏览器会特殊处理。比如 `href="#"` 和 `href="javascript:void(0)"`,这两个在 `.href` 下的表现完全不同。
`href="#"` 通过 `.href` 拿到的是当前页面URL加个 `#`。而 `getAttribute` 返回的就是 `"#"`。至于 `javascript:void(0)`,`.href` 会原样返回这个字符串——浏览器不会把它解析成URL。
我个人的习惯是:需要判断链接目标时用 `.href`,需要读写原始属性时用 `getAttribute` / `setAttribute`。混用迟早出问题。
用 `getAttribute('href')` 拿到的值,浏览器不会做任何URL编码处理。如果你的href里包含中文或特殊字符,拿到的是什么就是什么。但 `.href` 会自动进行百分号编码。
<a id="cn" href="/搜索?q=前端">搜索</a> cn.getAttribute('href'); // "/搜索?q=前端" cn.href; // "https://example.com/%E6%90%9C%E7%B4%A2?q=%E5%89%8D%E7%AB%AF" 需要把链接发到后端做签名或者比对的时候,编码差异能让你debug到怀疑人生。我吃过这个亏,一个搜索跳转功能在本地测试没问题,上线后中文参数全乱码。查了半天,就是 `.href` 自动编码导致的。
说到底,这两个属性没有谁更好,只有谁更合适。理解浏览器在背后做了什么,比死记API有用得多。