这是作为面试问题给我的 - 没有得到这份工作,但我还是想弄清楚。
目标是编写两个querySelectorAll
函数:一个名为qsa1
,用于由单个标记名称组成的选择符(例如div
或span
)和另一个名称qsa2
,它接受任意嵌套的标记选择器(例如p span
或ol li code
)。
我很容易得到第一个,但第二个有点棘手。
我怀疑,为了处理可变数量的选择器,正确的解决方案可能是递归的,但我想我会尝试使用迭代优先工作。这是我到目前为止所得到的:
qsa2 = function(node, selector) {
var selectors = selector.split(" ");
var matches;
var children;
var child;
var parents = node.getElementsByTagName(selectors[0]);
if (parents.length > 0) {
for (var i = 0; i < parents.length; i++) {
children = parents[i].getElementsByTagName(selectors[1]);
if (children.length > 0) {
for (var i = 0; i < parents.length; i++) {
child = children[i];
matches.push(child); // somehow store our result here
}
}
}
}
return matches;
}
我的代码的第一个问题,除了它不起作用的事实,它只处理两个选择器(但它应该能够清除第一,第二和第四种情况)。
第二个问题是我无法返回正确的结果。我知道,就像在qsa1
中一样,我应该返回与我通过调用getElementsByTagName()
函数得到的相同结果,其中&#34;返回实时NodeList
具有给定标签名称的元素&#34;。创建一个数组并将Node
推送或附加到它上面并不是要切割它。
如何撰写正确的回报结果?
(对于上下文,可以找到完整的代码体here)
答案 0 :(得分:0)
以下是我的做法
next
假设我们始终将文档作为上下文开始,然后将选择器拆分为空格,就像您已经在做的那样,并迭代标记名。
在每次迭代中,只需覆盖外部concat
变量,然后再次运行循环
我使用了一个数组并matches
将结果存储在循环中。
这有点类似于问题中的代码,但应该注意的是,您从不创建数组,实际上undefined
变量是pods
,并且无法推送到。
答案 1 :(得分:0)
这里有语法错误:
if (parents.length > 0) { for (var i = 0; i < parents.length; i++) { children = parents[i].getElementsByTagName(selectors[1]); if (children.length > 0) { for (var i = 0; i < parents.length; i++) { // <-----------------------
不要超过children
的长度,而是超过parent
的长度。
以及您正在重复使用迭代变量名称这一事实!这意味着映射到i
长度的parent
会在child
循环中被覆盖!
另外,如果元素为空,for
循环不会遍历元素,因此您的检查是多余的。
应该如下:
for (var i = 0; i < parents.length; i++) {
children = parents[i].getElementsByTagName(selectors[1]);
for (var k = 0; k < children.length; i++) {
我建议使用如下的递归解决方案,而不是使用迭代解决方案:
var matches = [];
function recursivelySelectChildren(selectors, nodes){
if (selectors.length != 0){
for (var i = 0; i < nodes.length; i++){
recursivelySelectChildren(nodes[i].getElementsByTagName(selectors[0]), selectors.slice(1))
}
} else {
matches.push(nodes);
}
}
function qsa(selector, node){
node = node || document;
recursivelySelectChildren(selector.split(" "), [node]);
return matches;
}