Javascript 自定义querySelectorAll实现

Javascript 自定义querySelectorAll实现,javascript,dom,selectors-api,Javascript,Dom,Selectors Api,这是作为面试问题给我的--我没有得到这份工作,但我仍然想弄清楚 目标是编写两个querySelectorAll函数:一个名为qsa1的函数用于由单个标记名(例如div或span)组成的选择器,另一个名为qsa2的函数用于接受任意嵌套的标记选择器(例如p span或ol li code). 我很容易得到第一个,但第二个有点棘手 我怀疑,为了处理数量可变的选择器,正确的解决方案可能是递归的,但我想我应该先尝试使用迭代的方法。以下是到目前为止我得到的信息: qsa2 = function(nod

这是作为面试问题给我的--我没有得到这份工作,但我仍然想弄清楚

目标是编写两个
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;
  }
qsa2=函数(节点、选择器){
变量选择器=选择器。拆分(“”);
var匹配;
儿童;
var-child;
var parents=node.getElementsByTagName(选择器[0]);
如果(parents.length>0){
对于(var i=0;i0){
对于(var i=0;i
我的代码的第一个问题是,除了无法工作之外,它只处理两个选择器(但它应该能够清除第一、第二和第四个案例)

第二个问题是我在返回正确的结果时遇到问题。我知道,正如在
qsa1
中一样,我应该返回与调用
getElementsByTagName()
函数相同的结果,该函数“返回具有给定标记名的元素的活动
NodeList
”。创建一个数组并将
节点压入或附加到该数组中并不是在剪切它

如何编写正确的返回结果

(对于上下文,可以找到完整的代码体)

以下是我的做法

function qsa2(selector) {
    var next = document;
    selector.split(/\s+/g).forEach(function(sel) {
        var arr = [];
        (Array.isArray(next) ? next : [next]).forEach(function(el) {
            arr = arr.concat( [].slice.call(el.getElementsByTagName(sel) ));
        });
        next = arr;
    });
    return next;
}
假设我们总是从文档作为上下文开始,然后像您已经做的那样在空格上拆分选择器,并迭代标记名。
在每次迭代中,只需覆盖外部
下一个
变量,然后再次运行循环。
我使用了一个数组和
concat
将结果存储在循环中

这有点类似于问题中的代码,但应该注意的是,您从未创建数组,事实上,
匹配的
变量是
未定义的
,无法推送到。

我将这样做

function qsa2(selector) {
    var next = document;
    selector.split(/\s+/g).forEach(function(sel) {
        var arr = [];
        (Array.isArray(next) ? next : [next]).forEach(function(el) {
            arr = arr.concat( [].slice.call(el.getElementsByTagName(sel) ));
        });
        next = arr;
    });
    return next;
}
假设我们总是从文档作为上下文开始,然后像您已经做的那样在空格上拆分选择器,并迭代标记名。
在每次迭代中,只需覆盖外部
下一个
变量,然后再次运行循环。
我使用了一个数组和
concat
将结果存储在循环中


这有点类似于问题中的代码,但应该注意的是,您从未创建数组,事实上,
匹配的
变量是
未定义的
,无法推送到。

此处有语法错误:


我建议使用如下递归解决方案,而不是使用迭代解决方案:

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;
}
var匹配=[];
函数递归选择子对象(选择器、节点){
如果(selectors.length!=0){
对于(var i=0;i
此处出现语法错误:


我建议使用如下递归解决方案,而不是使用迭代解决方案:

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;
}
var匹配=[];
函数递归选择子对象(选择器、节点){
如果(selectors.length!=0){
对于(var i=0;i
这台机器运行得很好!感谢您向我展示了如何成功地遍历DOM子树并形成返回数组。很明显,我仍然掌握着JS的窍门,你的评论非常有用。这很好用!感谢您向我展示了如何成功地遍历DOM子树并形成返回数组。显然,我仍然掌握着JS的窍门,你的评论非常有用。