为什么 getAttribute('href') return 与 reduce 一起使用时完整的 URL?

Why does getAttribute('href') return the full URL when used with reduce?

我有一个带有内部 ID 的锚点列表,我想 select 使用 .querySelectorAll() 的所有目标,例如:

const targets = document.querySelectorAll('#target-1, #target-2, …')

为了准备这个查询,我使用了 reduce:

anchors.reduce((previous, current, index) =>
    index === 0 ?
        current.getAttribute('href') :
        previous + ', ' + current.getAttribute('href')
)

这几乎可以工作,但有一个奇怪的问题,结果如下所示:

https://full-url.com/#target-1, #target-2, #target-3

当我只运行:

targets[0].getAttribute('href')

… returns 预期结果:

target-1

你可以自己试试:

const anchors = Array.from(document.querySelectorAll('a'));

console.log(anchors[0].getAttribute('href'));

console.log(anchors.reduce((previous, current, index) => index === 0 ? current.getAttribute('href') : previous + ', ' + current.getAttribute('href')));
<a href="#target-1"></a>
<a href="#target-2"></a>
<a href="#target-3"></a>


这至少在 Chrome、macOS 上的 Safari 和 Firefox 中会发生。

为什么完整的 URL 放在第一个元素之前?

发生这种情况是因为 reduce 需要传递初始值。尝试传递空字符串:

const anchors = Array.from(document.querySelectorAll('a'));
const first = anchors[0].getAttribute('href');
const all = anchors.reduce((previous, current, index) => index === 0 ? current.getAttribute('href') : previous + ', ' + current.getAttribute('href'), "");

/* The first 'href' value. */
console.log(first);

/* All 'href' values. */
console.log(all);

/* When concatenating an <a> element with a string, a link is returned. */
console.log(anchors[0] + "");
<a href="#target-1"></a>
<a href="#target-2"></a>
<a href="#target-3"></a>

如果不传递初始值,则使用数组的第一个元素。由于数组中的元素是 <a> 元素,因此整个 URL 是前置的,因为当您将锚元素与字符串连接时,锚元素将转换为实际的 link ( as described here).

您必须将空字符串作为初始值传递给回调函数:

let anchors = Array.from(document.querySelectorAll('a'));

 anchors = anchors.reduce((previous, current, index) => index === 0 ? current.getAttribute('href') : previous + ', ' + current.getAttribute('href'),"");
 console.log(anchors)
<a href="#target-1"></a>
<a href="#target-2"></a>
<a href="#target-3"></a>

如果您稍微更改代码,它会变得更少代码并且可以工作。您不必为此使用 reduce。这样你就不用 fiddle 初始值和累加值,只需将列表锚点转换为 hrefs 的列表 并加入……

const anchors = Array.from(document.querySelectorAll('a'));

const str = anchors.map(a => a.getAttribute('href')).join(',');
console.log(str);
<a href="#target-1"></a>
<a href="#target-2"></a>
<a href="#target-3"></a>

为什么会这样是因为reduce中的initialValue是可选的,如果不传就取数组的第一个索引作为初始值。因此,如果您记录第一个索引并对其进行 toString,您将看到完整的 url 以及散列。尝试

console.log(anchors[0].toString())

Here's 规格说明:

Value to use as the first argument to the first call of the callback. If no initial value is supplied, the first element in the array will be used. Calling reduce() on an empty array without an initial value is an error.

有关正确的代码,请参阅