将对象数组减少为在所有对象共享的属性中找到的唯一字符串(javascript)
我编写了一个javascript函数,它成功地返回HTML文档中使用的所有唯一类的数组将对象数组减少为在所有对象共享的属性中找到的唯一字符串(javascript),javascript,arrays,foreach,Javascript,Arrays,Foreach,我编写了一个javascript函数,它成功地返回HTML文档中使用的所有唯一类的数组 const elements = document.getElementsByTagName('*'); let classesUsedInHtml = htmlCollection => { let uniqClassSelectors = []; Array.from(htmlCollection) .filter(element => element.classList.l
const elements = document.getElementsByTagName('*');
let classesUsedInHtml = htmlCollection => {
let uniqClassSelectors = [];
Array.from(htmlCollection)
.filter(element => element.classList.length > 0)
.map(element =>
element.classList.forEach(
item =>
uniqClassSelectors.includes(item)
? null
: uniqClassSelectors.push(item)
)
);
return uniqClassSelectors;
};
console.log(classesUsedInHtml(elements));
我想使用Array.prototype.reduce()
重构此函数,并跳过定义变量uniqClassSelectors
的需要,但无法使其工作
这是我的重构函数,它不起作用(返回未定义的累加器)。在这方面,我经常被reduce()
绊倒。为什么累加器未定义?我是否在reduce()
函数中正确使用了forEach()
?有人能给我指一下正确的方向吗?谢谢
let classesUsedInHtml = htmlCollection => {
return Array.from(htmlCollection)
.filter(element => element.classList.length > 0)
.reduce((accumulator, element) => {
return element.classList.forEach(
classSelector =>
accumulator.includes(classSelector)
? accumulator
: accumulator.concat(classSelector)
);
}, []);
};
编辑:由于Nina Scholz注释,从相关函数中删除了不必要的map()
我建议对最终的domTokenList
使用另一个内部累加器,并将外部的累加器
作为内部累加器acc2
的起始值
let classesUsedInHtml = htmlCollection =>
Array
.from(htmlCollection)
.filter(element => element.classList.length)
.map(element => element.classList)
.reduce((accumulator, domTokenList) =>
domTokenList.reduce((acc2, classSelector) =>
acc2.concat(acc2.includes(classSelector) ? [] : classSelector),
accumulator
),
[]
);
另一个解决方案是使用收集唯一的类选择器
let classesUsedInHtml = htmlCollection =>
[...Array
.from(htmlCollection)
.filter(element => element.classList.length)
.map(element => element.classList)
.reduce((acc1, domTokenList) =>
domTokenList.reduce((acc2, classSelector) => acc2.add(classSelector), acc1),
new Set)
];
此解决方案的逐步指南。注释(//->)显示此步骤的结果,并将其传递到下一步
使用以下命令将htmlCollection
转换为数组:
将每个元素添加到类数组中(再次展开):
通过将子阵列展开到以下位置,将其展平:
将数组转换为,并展开回数组,以获取唯一的类名:
[...new Set([class, class, class, etc...])] // -> [class1, class2, class3, etc...]
const elements=document.getElementsByTagName('*');
const classesUsedInHtml=(htmlCollection)=>
[…新集合(//获取唯一项并转换为数组
[].concat(…//concat所有类的数组
[…htmlCollection]//将集合转换为数组
.map(({classList})=>[…classList])//获取类的数组
)
];
const result=classesUsedInHtml(元素);
控制台日志(结果)代码>
如果不获取返回值(在第一个代码中),为什么要映射?第二个不返回您想要的forEach
。它只返回未定义的。很好地捕捉到了@NinaScholz。我将更新上面的问题函数。但这并不能解决根本问题。DOMTokenList
不是一个数组,但它的原型中确实有forEach()
方法。因此,如果您添加Array.from(domTokenList).reduce…
,您的代码就可以工作。在数组上使用另一个reduce()
是个好主意。但是您知道如何使用forEach()
?正如我在评论中所写的那样,forEach
不会返回要使用的内容。在这种情况下,您需要一个外部变量,您希望消除它。所以,要么使用地图
,要么使用reduce获取新值。谢谢,在我发布之前没有看到您的更新评论。哇!我知道我不应该用评论来表示“谢谢”,但我以前不知道Set
。使用spread运算符时非常优雅,这正是我所寻求的方法。除了提供的注释之外,有人能解释整个解决方案中发生了什么吗?@BrianZ-我已经添加了一个解决方案的逐步分解。非常有用,您的说明从代码内部开始,然后流出。我从外到内阅读,然后迷路了。再次感谢!
[htmlElement, htmlElement, etc...].map(({ classList }) => [...classList])) // -> [[class, class, etc...], [class, class, etc...], etc...]
[].concat(...[[class, class, etc...], [class, class, etc...]], etc...) // -> [class, class, class, etc...]
[...new Set([class, class, class, etc...])] // -> [class1, class2, class3, etc...]