Разверните итеративный элемент или не повторяемый элемент в массив без проверки элемента.length
Дано html
<div></div>
<div></div>
призвание document.querySelector("div")
возвращает первое div
элемент, где .length
не является свойством возвращаемого значения.
призвание document.querySelectorAll()
возвращает NodeList
иметь .length
имущество.
Разница между двумя возвращаемыми значениями .querySelector()
а также .querySelectorAll()
является то, что первое не является итеративным; и ошибка будет выдана при попытке использовать spread element
развернуть элемент в массив.
В следующих примерах учтите, что либо div
или же divs
это параметр, полученный в теле вызова функции. Таким образом, насколько это возможно, невозможно определить, была ли переменная определена в результате Element.querySelector()
, Element.querySelectorAll()
, document.querySelector()
или же document.querySelectorAll()
; дальше разница между .querySelector()
а также .querySelectorAll()
можно проверить только с помощью .length
,
var div = document.querySelector("div");
for (let el of div) {
console.log(".querySelector():", el)
}
<div></div>
<div></div>
бревна
Uncaught TypeError: div[Symbol.iterator] is not a function
в то время как
var div = document.querySelectorAll("div");
for (let el of div) {
console.log(".querySelectorAll():", el)
}
<div></div>
<div></div>
возвращает ожидаемый результат; то есть, document.querySelectorAll("div")
расширяется, чтобы заполнить итеративный массив.
Мы можем получить ожидаемый результат в .querySelector()
установив div
как элемент Array
[div]
в for..of
iterable
параметр.
Самые близкие пришли к использованию одного и того же шаблона для обоих или .querySelector()
или же .querySelectorAll()
использует callback
из Array.from()
и .tagName
переменной и spread element
, Хотя это исключает дополнительные селекторы, которые могли быть вызваны с .querySelector()
, например .querySelector("div.abc")
,
var div = document.querySelector("div");
var divs = document.querySelectorAll("div");
var elems = Array.from({length:div.length || 1}, function(_, i) {
return [...div.parentElement.querySelectorAll(
(div.tagName || div[0].tagName))
][i]
});
for (let el of elems) {
console.log(".querySelector():", el)
}
elems = Array.from({length:divs.length || 1}, function(_, i) {
return [...divs[0].parentElement.querySelectorAll(
(divs.tagName || divs[0].tagName))
][i]
});
for (let el of elems) {
console.log("querySelectorAll:", el)
}
<div></div>
<div></div>
Это не обеспечивает адекватной точности по дополнительным причинам; Element.querySelector()
мог быть первоначально передан в функцию, а не document.querySelector()
аналогично для .querySelectorAll().
Not sure if it is possible to retrieve the exact selector passed to
.querySelector, All` без модификации нативной функции?
Требуемый шаблон будет принимать переменную и расширять содержимое итерируемого в массив, если .querySelectorAll()
использовался; что бы лечить .getElementsByTagName()
, .getElementsByClassName()
, .getElementsByTagName()
, .getElementsByName()
тот же самый; или установите единственное значение, возвращаемое .querySelector()
как элемент массива.
Обратите внимание, что текущее рабочее решение
div.length ? div : [div]
который повторяется div
если div
имеет .length
свойство, возможно, повторяемое, хотя просто .length
собственность и не быть iterable
; еще установить div
как отдельный элемент массива, итеративный.
var div = document.querySelector("div");
var divs = document.querySelectorAll("div");
var elems = div.length ? div : [div];
for (let el of elems) {
console.log(".querySelector():", el)
}
var elems = divs.length ? divs : [divs];
for (let el of elems) {
console.log("querySelectorAll:", el)
}
<div></div>
<div></div>
Может ли это быть достигнуто
- без проверки
.length
переменной? - без ссылки на элемент три раза в одной строке?
Может подход рабочего решения
- быть улучшенным; это должно
[Symbol.iterator]
изdiv
проверяться вместо.length
? - есть ли магия, использующая
.spread element
или жеrest element
что может позволить пропустить проверку.length
объекта? - будет использовать
Generator
,Array.prototype.reduce()
или другой подход изменить необходимость проверки.length
или же[Symbol.iterator]
свойство переменной перед расширением элемента в массив?
Или, является ли приведенный выше подход максимально кратким, учитывая разницу между iterable
или нет iterable
?
1 ответ
Я бы сделал более или менее, что Array.from
делает, но проверьте тип length
вместо того, чтобы всегда преобразовывать это:
const itemsOrSingle = items => {
const iteratorFn = items[Symbol.iterator]
if (iteratorFn) {
return Array.from(iteratorFn.call(items))
}
const length = items.length
if (typeof length !== 'number') {
return [items]
}
const result = []
for (let i = 0; i < length; i++) {
result.push(items[i])
}
return result
}