将一个可迭代元素或非可迭代元素展开到数组中,而不必检查元素.length [英] Expand an iterable element or non-iterable element into an array without checking element .length

查看:204
本文介绍了将一个可迭代元素或非可迭代元素展开到数组中,而不必检查元素.length的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定 html

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

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



调用 document.querySelectorAll()返回一个 NodeList $ c> .length 属性。



两个返回值 .querySelector() .querySelectorAll()是前者不是可迭代的;并且尝试使用传播元素将元素展开为数组时,将抛出错误。



在以下示例认为 div divs 是函数调用正文中接收的参数。因此,尽可能收集,不可能确定变量是否定义为 Element.querySelector()元素的结果。 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>  



日志

 未捕获TypeError :div [Symbol.iterator]不是一个函数



  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] 

at for..of iterable 参数。



最接近的是使用相同的模式,既可以使用相同的模式,也可以使用 .querySelector() .querySelectorAll )使用回调 Array.from() .tagName spread元素
虽然这省略了可能使用 .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。长度|| 1},函数(_,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() code> .querySelectorAll()。
不确定是否可以检索传递给
.querySelector,All而不修改本机函数的确切选择器。



如果使用 .querySelectorAll(),则所需的模式将接受变量,并将iterable的内容扩展为数组。这将处理 .getElementsByTagName() .getElementsByClassName() .getElementsByTagName() / code>, .getElementsByName()相同;或者将 .querySelector()返回的单个值设置为数组的元素。



注意,目前的工作方案是

  div.length? div:[div] 

其中迭代 div 如果 div 有一个 .length 属性,可能是一个可迭代的,虽然只是一个 .length 属性,而不是 iterable ;否则将 div 作为数组的单个元素,可迭代。



 

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



可以实现




  • 不检查 .length 的变量?

  • 没有在同一行引用元素三次?



可以使用工作方案的方法




    <改善;这应该是 [Symbol.iterator] div ,而不是 .length
  • 是使用 .spread元素 rest元素可以省略检查对象的 .length

  • 将使用 Generator Array.prototype.reduce()或其他方法更改需要检查 .length [Symbol.iterator] 将元素扩展为数组之前的一个变量的属性



或者,上述方法可以简化,给出对象之间的差异,这些对象是 iterable 或不是 iterable

解决方案

我会做或多或少的什么 Array.from 确实,但检查 length 而不是总是转换它:

  const itemsOrSingle = items => {
const iteratorFn = items [Symbol.iterator]

if(iteratorFn){
返回Array.from(iteratorFn.call(items))
}

const length = items.length

if(typeof length!=='number'){
return [items]
}
$ ($ i $)


b
$ b返回结果
}


Given html

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

calling document.querySelector("div") returns the first div element, where .length is not a property of the return value.

Calling document.querySelectorAll() returns a NodeList having a .length property.

The difference between the two return values of .querySelector() and .querySelectorAll() is that the former is not an iterable; and error will be thrown when attempting to use the spread element to expand the element into an array.

In the following examples consider that either div or divs is a parameter received within the body of a functions call. Thus, as far as can gather, it is not possible to determine if the variable was defined as a result of Element.querySelector(), Element.querySelectorAll(), document.querySelector() or document.querySelectorAll(); further the difference between .querySelector() and .querySelectorAll() can only be checked using .length.

var div = document.querySelector("div");
for (let el of div) {
  console.log(".querySelector():", el)
}

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

logs

Uncaught TypeError: div[Symbol.iterator] is not a function

while

var div = document.querySelectorAll("div");
for (let el of div) {
  console.log(".querySelectorAll():", el)
}

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

returns expected result; that is, document.querySelectorAll("div") is expanded to fill the iterable array.

We can get the expected result at .querySelector() by setting div as an element of an Array

[div]

at for..of iterable parameter.

The closest have come to using same pattern for both or either .querySelector() or .querySelectorAll() is using callback of Array.from() and the .tagName of the variable, and spread element. Though this omits additional selectors that may have been called with .querySelector(), for example .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>

This does not provide adequate accuracy for additional reasons; Element.querySelector() could have been originally passed to function, instead of document.querySelector(), similarly for .querySelectorAll(). Not sure if it is possible to retrieve the exact selector passed to.querySelector, All` without modifying the native function?

The desired pattern would accept the variable, and expand the contents of the iterable into an array if an .querySelectorAll() was used; which would treat .getElementsByTagName(), .getElementsByClassName(), .getElementsByTagName(), .getElementsByName() the same; or set the single value returned by .querySelector() as element of the array.

Note, the current working solution is

div.length ? div : [div]

which iterates div if div has a .length property, possibly an iterable, though simply have a .length property and not be an iterable; else set div as single element of an array, an iterable.

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>

Can this be achieved

  • without checking the .length of the variable?
  • without referencing the element three times on same line?

Can the approach of the working solution

  • be improved; that is should [Symbol.iterator] of div be checked instead of .length?
  • is there magic using .spread element or rest element which could allow omission of checking .length of object?
  • would using a Generator, Array.prototype.reduce() or other approach change the need to check the .length or [Symbol.iterator] property of a variable before expanding the element into an array?

Or, is the above the approach the briefest possible given the difference between objects which are iterable or not iterable?

解决方案

I’d do more or less what Array.from does, but check the type of length instead of always converting it:

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
}

这篇关于将一个可迭代元素或非可迭代元素展开到数组中,而不必检查元素.length的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆