Почему getAttribute ('href') возвращает полный URL-адрес при использовании с reduce?

У меня есть список якорей с внутренними идентификаторами, и я хочу выбрать все цели, используя .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')

… Возвращает ожидаемый результат:

target-1

Можете попробовать сами:

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

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

console.info(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, Safari и Firefox на macOS.

Почему к первому элементу добавляется полный URL-адрес?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
217
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Это происходит потому, что 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.info(first);

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

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

Если вы не передаете начальное значение, используется первый элемент массива. Поскольку элементы в вашем массиве являются элементами <a>, весь URL-адрес добавляется в начало, потому что, когда вы объединяете элемент привязки со строкой, элемент привязки преобразуется в фактическую ссылку (как описано здесь).

Я согласен, что они должны это сделать, но объяснение того, что происходит, может быть хорошим дополнением.

Kaiido 06.09.2018 12:33

Хорошо, но почему кажется, что в качестве начального значения используется полный URL-адрес?

Luca Kiebel 06.09.2018 12:33

Ах, понятно - я упустил изначальную ценность. Также хорошее объяснение, почему значение по умолчанию не оценивается как ''. Спасибо.

lampshade 06.09.2018 12:43

Вы должны передать пустую строку в качестве начального значения функции обратного вызова:

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

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

Я согласен, что они должны это сделать, но объяснение того, что происходит, может быть хорошим дополнением.

Kaiido 06.09.2018 12:33

Если немного изменить код, он становится меньше кода и работает. Для этого не обязательно использовать reduce. Таким образом, вы не возитесь с начальным и накопленным значением, просто преобразуйте якоря списка в список имеющихся href. и присоединяйтесь к этому ...

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

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

Спасибо, я согласился с этим кодом, так как его легче поддерживать. : D

lampshade 06.09.2018 12:39

Это происходит потому, что initialValue в сокращении является необязательным, если он не передан, он принимает первый индекс массива в качестве начального значения. Итак, если вы зарегистрируете первый индекс и toString его, вы увидите полный URL-адрес вместе с хешем. Пытаться

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

Вот что сказано в спецификации:

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.

Правильный код см. В Ответ ангела.

Другие вопросы по теме