querySelector: return为null时如何不调用函数?

querySelector: how not to call function when return is null?

提问人:Tom 提问时间:10/6/2023 最后编辑:Mark RotteveelTom 更新时间:10/25/2023 访问量:189

问:

我需要对 DOM 中可能存在也可能不存在的元素执行一个函数,使用 (不是 ,因为最多会有一个这样的元素)。我能设计出的最优雅的解决方案是:querySelectorquerySelectorAll

(function (element) {
    if (element) {
        [business logic of the function]
    }
}(document.querySelector([css selector])));

目标是,如果 不返回元素,则根本不调用该函数。(如果未找到匹配的元素,则返回。querySelectorquerySelectornull

我最初的问题缺乏明确的标准,我对回答的反对意见导致该问题以基于意见而结束。标准如下:

我想解决这个问题,而不必声明例程外部的变量,例如,不是:

let x = document.querySelector([css selector]);
if (x) {
    [business logic on x]
};

我想要像document.querySelectorAll这样优雅的东西,它返回一个可迭代的NodeList(或null),在执行工作之前不需要对返回的数据进行测试。即,

document.querySelectorAll([css selector]).forEach(function (element) {
    [business logic using element]
});

querySelectorAll这里是矫枉过正,因为我最多返回 1 个元素,如果什么都没有返回,就不会运行任何业务逻辑。

目前,我能看到的唯一方法是:将返回值传递给函数,并在继续函数工作之前检查函数的返回值是否为假。

如果 的返回不是元素,有没有一种优雅的方法可以调用该函数?querySelector

同样,我不想使用 ,因为最多有一个元素与 .当前解决方案的美妙之处在于它依赖于匿名函数,并且不需要创建显式变量(使用 or ),因为该函数提供了一个用于传递的参数。querySelectorAllquerySelectorvarlet

JavaScript 函数 queryselector dom-traversal

评论

1赞 Đinh Carabus 10/6/2023
取决于业务逻辑。如果是对该元素的单个方法调用,则可以使用 。document.querySelector(...)?.someMethod(...)
1赞 Phil 10/6/2023
@AfzalK。在问题的任何地方都没有这么说
1赞 Tom 10/7/2023
请注意,querySelectorAll() 解决了这个问题,但它是矫枉过正的。有了它,你可以做 如果什么都没有返回,则不调用该函数。我本质上是在为.document.querySelectorAll([selector]).forEach((element) => { [business logic] });querySelector
2赞 Đinh Carabus 10/7/2023
@Tom,我认为这看起来很傻,但它满足了您不使用 querySelectorAll 的要求::)[document.querySelector([selector])].filter(Boolean).forEach(function(element) { [business logic] })
1赞 Đinh Carabus 10/7/2023
@Tom,当然,但是在立即调用的函数表达式中以某种方式不调用函数表达式是不可能的。

答:

0赞 Barmar 10/6/2023 #1

您可以在语句中赋值变量。if

let element;
if (element = document.querySelector("selector")) {
    // do something with element
}

评论

0赞 Tom 10/7/2023
这确实更短,但我不想明确定义“元素”。
0赞 Barmar 10/7/2023
那么,没有什么比您的解决方案更好的了。
0赞 Barmar 10/7/2023
与 不同,您不能将变量声明直接放在条件中。forif
1赞 Bergi 10/7/2023
@Barmar所以?不寒而栗for (let element = document.querySelector("selector"); element; element = null) { … }
1赞 Barmar 10/7/2023
@Bergi呃,就在那里switch(true) { case condition1: ... case condition2: ... }
0赞 Tom 10/7/2023 #2

Đinh-carabus 在上面的评论中提出的方法可能最接近我正在寻找的解决方案,但前提是要抽象成一个可以根据需要调用的函数,即:

function myQuerySelector(selector, func) {
    Array.from(document.querySelector(selector)).filter(Boolean).forEach(func);
}

// trivial use case:
myQuerySelector('body', function (element) {
    console.log(element);
});

一个不太复杂的解决方案,可以在不调用原始函数的情况下使用,但这个解决方案可能具有一般价值,所以我把它作为一个解决方案发布在这里。

评论

1赞 Bergi 10/7/2023
好吧,如果你无论如何都要使用辅助函数,你不妨在那里使用一个普通的语句,而不是这个难以理解的语法。if
2赞 Bergi 10/7/2023
此外,至少使用数组文字而不是新数组
0赞 Afzal K. 10/7/2023
这是一个更简短的版本:[...document.querySelectorAll('div')].forEach(function(element) { console.log(element); });
0赞 Tom 10/8/2023
Afzal K.,在这种情况下,我想避免querySelectorAll()。
1赞 Tom 10/8/2023
@AfzalK。此外,您提出的建议与 无需传播的结果相同,因为它返回了一个可以直接调用的可迭代节点列表。document.querySelectorAll('div').forEach(function (element) { console.log(element); });querySelectorAll.forEach
1赞 Bergi 10/7/2023 #3

我不想使用 ,因为最多有一个元素与选择器匹配querySelectorAll

您可能需要重新考虑这一立场。这是一个完美的用例:您希望获得一个集合,其中包含文档中与选择器匹配的所有元素。如果你的文档最多包含一个这样的元素,那没关系,你会得到一个包含 0 或 1 个元素的集合 - 这并不能改变这只是获取 N 个元素的特例这一事实。querySelectorAll

使用此方法,代码简短易行:

document.querySelectorAll(…).forEach(element => {
    … // business logic
});

for (const element of document.querySelectorAll(…)) {
    … // business logic
}

如果多次执行逻辑看起来很奇怪,请添加注释以解释选择器匹配 0 或 1 个元素。


也就是说,我看不出有什么问题

(element => {
    if (!element) return;
    … // business logic
})(document.querySelector(…));

如果你真的需要一个特殊的语法,可以编写你自己的帮助程序函数,或者看看一些管道运算符的讨论,这些讨论提出了可选的流水线,比如

document.querySelector(…) ?> (element => {
    … // business logic
});

不过,您需要为此编写自己的转译器插件或宏。

评论

0赞 Tom 10/7/2023
正如您多年来所描述的那样,我一直在使用 querySelectorAll(),用于会有很多匹配元素的情况,但是当我使用它时,我总是畏缩不前,因为我只需要抓取一个元素,但又要防止该元素可能不存在的边缘情况。我想使用一个更短/不同的例程来处理我知道应该只存在一个这样的元素的情况;因此,除其他好处外,使用不同的例程将是例程预期的视觉指标。