javascript - 将可迭代元素或不可迭代元素扩展为数组而不检查元素 .length

标签 javascript arrays ecmascript-6 iterable

给定 html

<div></div>
<div></div>

调用 document.querySelector("div") 返回第一个 div 元素,其中 .length 不是返回值的属性。

调用 document.querySelectorAll() 返回具有 NodeList 属性的 .length
.querySelector().querySelectorAll()这两个返回值的区别在于前者不是可迭代的;尝试使用 spread element 将元素扩展为数组时将引发错误。

在以下示例中,请考虑 divdivs 是函数调用主体中接收的参数。因此,据我们所知,无法确定变量是否定义为 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() 使用 callbackArray.from() 和变量的 .tagNamespread 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` 而不修改 native 函数?

如果使用了 .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 elementrest element 是否有魔法可以允许省略检查对象的 .length
  • 会使用 GeneratorArray.prototype.reduce() 或其他方法改变在将元素扩展为数组之前检查变量的 .length[Symbol.iterator] 属性的需要吗?

  • 或者,考虑到 iterable 或非 iterable 对象之间的差异,上述方法是否是最简洁的?

    最佳答案

    我或多或少会做what Array.from does , 但检查 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
    }
    

    关于javascript - 将可迭代元素或不可迭代元素扩展为数组而不检查元素 .length,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40198807/

    相关文章:

    Javascript 替换子/循环问题

    arrays - numpy 数组的最大大小是多少?

    javascript - 在javascript中使用php数组填充 'select' ajax

    javascript - 如何在 JavaScript 中有效地比较一个对象数组与另一个数组?

    javascript - 用于匹配字符串开头和结尾的两个单引号的正则表达式

    javascript - 删除 DOM 中的元素

    滚动时更改标题颜色的JavaScript

    ecmascript-6 - 什么是 () => 运算符?

    javascript - 从 Material 表中的 React 状态动态查找

    java - 从 JAVA + StackOverflowError 中的集合项生成唯一对