jQuery是否会对"选择器"进行任何缓存?

All*_*nde 58 jquery jquery-selectors

例如,第一段代码是否会执行两次完整搜索,或者如果没有发生DOM更改,它是否足够智能以缓存结果?

if ($("#navbar .heading").text() > "") {
  $("#navbar .heading").hide();
}
Run Code Online (Sandbox Code Playgroud)

var $heading = $("#navbar .heading");

if ($heading.text() > "") {
  $heading.hide();
}
Run Code Online (Sandbox Code Playgroud)

如果选择器更复杂,我可以想象它是一个非平凡的命中.

gna*_*arf 29

始终缓存您的选择!

$( selector )使用相同的选择器不断地一遍又一遍地调用是浪费的.

或者几乎总是......你通常应该在局部变量中保存jQuery对象的缓存副本,除非你期望它已经改变或者你只需​​要它一次.

var element = $("#someid");

element.click( function() {

  // no need to re-select #someid since we cached it
  element.hide(); 
});
Run Code Online (Sandbox Code Playgroud)

  • `element.hide()` 通常更好,除非您希望闭包处理多个元素,因此将其绑定到 `$(this)`。但是,如果您担心这些事情中的任何一个的“性能”,那么您就会遇到不切实际的优化案例。无论是作用域链还是 `$(this)` 都不会成为任何应用程序中的瓶颈。 (2认同)

Nei*_*ski 16

jQuery没有,但是有可能在表达式中分配变量,然后在后续表达式中重用它们.所以,缓存 - 如果你的例子......

if ((cached = $("#navbar .heading")).text() > "") {
  cached.hide();
}
Run Code Online (Sandbox Code Playgroud)

缺点是它使代码有点琐碎,难以理解.

  • 在许多情况下,它不需要使用变量将所选元素存储在干净命名的组中. (5认同)
  • 我刚刚编写了一个轻量级插件,可以为您缓存选择器,同时保持代码干净.https://github.com/farzher/jQuery-Selector-Cache (3认同)
  • 注意:请确保在声明变量时你们使用`var`关键字,这样它们就不会被不必要地提升到全局范围内. (2认同)

Joe*_*ggs 14

这不是"它是什么?"的问题,而是"可以吗?",不,它不能 - 自上次运行查询以来,您可能已经向DOM添加了其他匹配元素.这会使缓存的结果失效,并且除了再次运行查询之外,jQuery没有(合理的)方式来告诉其他人.

例如:

$('#someid .someclass').show();
$('#someid').append('<div class="someclass">New!</div>');
$('#someid .someclass').hide();
Run Code Online (Sandbox Code Playgroud)

在此示例中,如果查询有任何缓存,则不会隐藏新添加的元素 - 它将仅隐藏先前显示的元素.

  • 它可以检测调用之间的dom更改并使缓存无效.如果这就是它的设计方式. (5认同)

Ale*_*kov 12

我刚刚做了一个解决这个问题的方法:

var cache = {};

function $$(s)
{
    if (cache.hasOwnProperty(s))
    {
        return $(cache[s]);
    }

    var e = $(s);

    if(e.length > 0)
    {
        return $(cache[s] = e);
    }

}
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:

$$('div').each(function(){ ... });
Run Code Online (Sandbox Code Playgroud)

基于这个简单的检查,结果是准确的,据我所知:

console.log($$('#forms .col.r')[0] === $('#forms .col.r')[0]);
Run Code Online (Sandbox Code Playgroud)

注意,它会破坏您的MooTools实现或使用$$符号的任何其他库.


Pet*_*ton 9

我不认为它(虽然我现在不想通过阅读三千五百行的JavaScript来确定).

但是,你正在做的不需要多个选择器 - 这应该工作:

$("#navbar .heading:not(:empty)").hide();
Run Code Online (Sandbox Code Playgroud)


Sef*_*man 6

与你的$$方法类似,我创建了一个函数(同名),它使用记忆模式来保持全局清洁,并且还考虑了第二个上下文参数......比如$$(".class","#content" ).如果你使用返回$$后发生的链式函数find(),则需要这样做; 因此,除非先缓存上下文对象,否则不会单独缓存它.我还在末尾添加了布尔参数(第二个或第三个参数,具体取决于你是否使用了上下文)来强制它返回到DOM.

码:

function $$(a, b, c){
    var key;
    if(c){
        key = a + "," + b;
        if(!this.hasOwnProperty(key) || c){
            this[key] = $(a, b);
        }        
    }
    else if(b){
        if(typeof b == "boolean"){  
            key = a;  
            if(!this.hasOwnProperty(key) || b){
                this[key] = $(a);
            }
        }
        else{
            key = a + "," + b;
            this[key] = $(a, b);   
        }            
    }
    else{
        key = a;
        if(!this.hasOwnProperty(key)){
            this[key] = $(a);
        } 
    }
    return this[key]; 
}
Run Code Online (Sandbox Code Playgroud)

用法:

<div class="test">a</div>
<div id="container">
    <div class="test">b</div>
</div>?

<script>
  $$(".test").append("1"); //default behavior
  $$(".test", "#container").append("2"); //contextual 
  $$(".test", "#container").append("3"); //uses cache
  $$(".test", "#container", true).append("4"); //forces back to the dome
?
</script>
Run Code Online (Sandbox Code Playgroud)