【问题标题】:jQuery pitfalls to avoid [closed]要避免的 jQuery 陷阱[关闭]
【发布时间】:2010-11-16 18:53:49
【问题描述】:

我正在使用 jQuery 开始一个项目。

您的 jQuery 项目中有哪些陷阱/错误/误解/滥用/误用?

【问题讨论】:

  • 这应该因为“不具建设性”而被关闭。一些非常有用的答案已经成为现实,这个问题现在已经被加星标了 220 次。如果你有足够的业力,请投票重新开放。
  • 在我看来,jQuery 本身就是一个陷阱

标签: javascript jquery


【解决方案1】:

不知道性能损失并过度使用选择器而不是将它们分配给局部变量。例如:-

$('#button').click(function() {
    $('#label').method();
    $('#label').method2();
    $('#label').css('background-color', 'red');
});

而不是:-

$('#button').click(function() {
    var $label = $('#label');
    $label.method();
    $label.method2();
    $label.css('background-color', 'red');
});

或者even better with chaining:-

$('#button').click(function() {
    $("#label").method().method2().css("background-color", "red"); 
});

当我意识到调用堆栈的工作原理时,我发现this 是一个启发性的时刻。

编辑:在 cmets 中合并建议。

【讨论】:

  • +1 用于 youtube 链接。天哪,我学到了很多东西。
  • 我认为将事物分配给局部变量很棒,但不要忘记链接的力量(来自您的示例): $("#label").method().method2().css ("背景色", "红色");
  • YouTube 视频很棒。我看过其他关于该主题的 Google 演示文稿,并且我仍然学到了一些东西!谢谢!
  • 链接也加1,太好了!
  • 在 jQuery 上下文中使用美元符号表示变量是一种约定。所以你可能想写var $label = $('#label');
【解决方案2】:

了解如何使用上下文。通常,jQuery 选择器会搜索整个文档:

// This will search whole doc for elements with class myClass
$('.myClass');

但是您可以通过在上下文中搜索来加快速度:

var ct = $('#myContainer');
// This will search for elements with class myClass within the myContainer child elements
$('.myClass', ct);

【讨论】:

  • 啊啊啊啊!好吧,这大约是我修复的 1,000,000 个错误。 +1
  • 感谢 JP 指出这一点。现在,该怎么办...我是否应该删除我的答案,这样其他人就不会胡思乱想并无缘无故地更改他们的代码?
  • 不,这仍然是一个好点,优化方面。 :)
  • jQuery 检查上下文是否是 jQuery 的实例,因此没有理由使用 [0]$('.myClass', ct); 或者如果你知道 ct 是 jQuery 的一个实例,你可以使用 find ct.find(".myClass")
【解决方案3】:

不要使用裸类选择器,像这样:

$('.button').click(function() { /* do something */ });

这最终会查看每一个元素,看它是否有一个“按钮”类。

相反,您可以帮助它,例如:

$('span.button').click(function() { /* do something */ });
$('#userform .button').click(function() { /* do something */ });

我去年从 Rebecca Murphy's blog 学到的

更新 - 这个答案是 2 年前给出的,对于 current 版本的 jQuery 来说是不正确的。 其中一个 cmets 包括一个测试来证明这一点。 还有一个updated version of the test,其中包含此答案时的 jQuery 版本。

【讨论】:

  • 我也觉得情况正好相反。也许在没有实现 getElementsByClassName 的浏览器中就是这种情况,但否则你只是给 jQuery 更多的工作要做。我非常希望看到 Rebecca 发布一些基准 :)
  • 您正在减少必须完成的工作量。这就像告诉某人把你的袜子从梳妆台的抽屉里拿出来,而不是告诉他们把袜子从你的房间里拿出来。大大减少了“看”的次数。
  • 当你写 CSS(至少包括元素标签)时,情况正好相反。见code.google.com/speed/page-speed/docs/…
  • @Sneakyness 并非所有事物都有真实生活的准确模拟。例如,$('.b') 可以在浏览器支持的情况下使用document.getElementsByClassName('b'),但执行$('a.b') 将导致它获取所有与b 类匹配的元素,然后在两阶段操作中确认它们是锚点。后者对我来说听起来像是更多的工作。对于现实生活中的类比,试试这个:找到我房间里的所有袜子。现在,扔掉那些不在我梳妆台里的。
  • 我认为对选择器的误解是由于在旧版本的 jquery 中,使用 $('#foo') 而不是 $('div#foo') 更快,因为根据定义,id 是唯一的。我很确定这在以后的版本中已修复,但该建议仅适用于 id,不适用于其他类型的选择器
【解决方案4】:

尝试拆分匿名函数,以便您可以重复使用它们。

//Avoid
$('#div').click( function(){
   //do something
});

//Do do
function divClickFn (){
   //do something    
}

$('#div').click( divClickFn );

【讨论】:

  • 我认为这适用于同步(内联)代码应该被分解为命名函数的程度大致相同。如果你有一大段代码要求给你一个名字,那就去吧。但是不要仅仅因为将代码包装在函数中而将代码移出行列;匿名函数的存在是有充分理由的。
  • 其实我喜欢给我的函数命名。当您调试代码时,它非常有用,您看到的不是无穷无尽的匿名函数列表,而是正确命名的函数。
  • 你的观点很好,我自己可能被这个绊倒了几次。即便如此,“大致相同的程度”仍然对我有用。
  • 特别是。如果绑定是在循环中发生的!
  • 命名函数在调试时也让你受益匪浅;没有什么比查看只有(anonymous) 的 8 级调用堆栈更糟糕的了。在此处阅读有关此提示的更多信息:stackoverflow.com/questions/182630/jquery-tips-and-tricks/…
【解决方案5】:
  • 避免滥用准备好的文档。
  • 保持文档为初始化代码做好准备。
  • 始终在准备好的文档之外提取函数,以便可以重复使用它们。

我在 doc ready 语句中看到了数百行代码。丑陋、不可读且无法维护。

【讨论】:

  • +1。一般来说,我见过的大部分 jQuery 代码都使用了数百行的函数。我不知道为什么“jQuery 开发者”不喜欢使用更小的函数。
  • @SolutionYogi 因为大多数只是 JS 菜鸟?
  • 我完全赞成没有将很长的函数放入准备好的文档中,这是个好建议。但是,让许多小组件功能从一个未准备好文档的总体功能运行不一定是最佳实践。如果总体功能是唯一使用这些代码的功能,那么最好将它们全部放在一个功能中,即使它更难阅读。调用函数有很多开销,如果你只在一个上下文中使用代码,应该避免它。
【解决方案6】:

在使用$.ajax 函数对服务器进行Ajax 请求时,应避免使用complete 事件来处理响应数据。无论请求是否成功,它都会触发。

而不是complete,使用success

请参阅文档中的 Ajax Events

【讨论】:

  • 我一直在成功与完整之间来回讨论,您能否详细说明为什么您认为完整更好?
  • 我并不是说完整更好。我想说的是,您需要避免误导性使用 complete 并且应该使用 success 以便能够处理响应数据。
  • 它总是被调用。但是我不同意。 Complete 最适合隐藏加载 gif 等。当然,您应该使用成功来处理响应和错误来处理任何错误。
  • 他建议使用success而不是complete。当 ajax 请求“完成”时,“完成”总是会触发,不管它是否成功完成。
  • @redsquare,您能否详细说明您不同意的内容?我指的是数据处理,不介意任何图片隐藏/显示完整处理程序的机会。
【解决方案7】:

带有回调的“链接”动画事件。

假设您想为点击后消失的段落制作动画。之后您还想从 DOM 中删除该元素。您可能认为您可以简单地将方法链接起来:

$("p").click(function(e) {
  $(this).fadeOut("slow").remove();
});

在这个例子中,.remove() 将在 .fadeOut() 完成之前被调用,破坏你的渐变效果,只是让元素立即消失。相反,如果您只想在完成前一个命令后触发命令,请使用回调:

$("p").click(function(e){
  $(this).fadeOut("slow", function(){
    $(this).remove();
  });
});

.fadeOut() 的第二个参数是一个匿名函数,它将在 .fadeOut() 动画完成后运行。这会导致逐渐褪色,并随后移除元素。

【讨论】:

    【解决方案8】:

    如果你多次 bind() 同一个事件,它会触发多次。为了安全起见,我通常总是去unbind('click').bind('click')

    【讨论】:

    • 这不是 jQuery 特有的,但要牢记这一点很重要。
    • 您可以使用实时事件不必绑定同一个事件两次。
    • live 如果习惯过度,会有其自身的(性能)问题。在 1.3.3 中更好,您可以提供上下文。
    【解决方案9】:

    不要滥用插件。

    大多数时候,您只需要库,也许还需要用户界面。如果您保持简单,那么您的代码将长期可维护。并非所有插件都受支持和维护,实际上大多数不是。如果您可以使用核心元素模仿功能,我强烈推荐它。

    插件很容易插入到您的代码中,为您节省一些时间,但是当您需要额外的东西时,修改它们是个坏主意,因为您会丢失可能的更新。您在开始时节省的时间会在以后更改已弃用的插件时丢失。

    明智地选择您使用的插件。 除了库和用户界面,我经常使用$.cookie$.form$.validatethickbox。其余的我主要开发自己的插件。

    【讨论】:

    • 网格呢?你自己做的?
    • 是的。从项目到项目的数据以各种方式出现。我更喜欢完全控制,因为意识到网格只会帮助我到达中间,然后我必须即兴发挥。
    • IF{ 如果有足够的时间,通常我更喜欢直接编写所有数据驱动的 dom 操作 (css/html) 代码。换句话说 - 不要将数据传递给“插件”并让它喷出 html。它很难评估(中场)插件的当前范围兼容性,忘记未来的需求。想想……设计师、规划师、经理、经理、经理。哦,还有客户和用户。但是,如果您拥有所有这些东西,那么您将没有足够的“时间”。所以就去使用 jqgrid - 你在浪费时间考虑。完成了吗?}
    【解决方案10】:

    陷阱:使用循环而不是选择器。

    如果你发现自己使用 jQuery '.each' 方法来迭代 DOM 元素,问问自己是否可以使用选择器来获取元素。

    更多关于 jQuery 选择器的信息:
    http://docs.jquery.com/Selectors

    陷阱:不使用 Firebug 之类的工具

    Firebug 实际上是为这种调试而设计的。如果您打算在 DOM 中使用 Javascript 搞砸,您需要一个像 Firebug 这样的好工具来提供可见性。

    有关 Firebug 的更多信息: http://getfirebug.com/

    本期多态播客中还有其他很棒的想法: (戴夫·沃德的 jQuery 秘密) http://polymorphicpodcast.com/shows/jquery/

    【讨论】:

    • 第一个我已经做过很多次了。您只需要记住,大多数 jQuery 函数将对从选择器返回的所有元素进行操作。
    • 老实说不喜欢 .each 方法
    【解决方案11】:

    在正确的上下文中使用此标识符的误解。例如:

    $( "#first_element").click( function( event)
    {
       $(this).method( ); //referring to first_element
       $(".listOfElements").each( function()
       {
          $(this).someMethod( ); // here 'this' is not referring first_element anymore.
       })
    });
    

    这里是您如何解决它的示例之一:

    $( "#first_element").click( function( event)
    {
       $(this).method( ); //referring to first_element
       var $that = this;
       $(".listOfElements").each( function()
       {
          $that.someMethod( ); // here 'that' is referring to first_element still.
       })
    });
    

    【讨论】:

    • +1 更多的是 javascript 问题而不是 jquery 问题,但我经常被这个问题绊倒。
    【解决方案12】:

    避免多次搜索整个 DOM。这确实会延迟您的脚本。

    不好:

    $(".aclass").this();
    $(".aclass").that();
    ...
    

    好:

    $(".aclass").this().that();
    

    不好:

    $("#form .text").this();
    $("#form .int").that();
    $("#form .choice").method();
    

    好:

    $("#form")
        .find(".text").this().end()
        .find(".int").that().end()
        .find(".choice").method();
    

    【讨论】:

    • $(".aclass").this().that();不好!仅类选择器很慢
    • 这是一个说明性示例,展示了 Jquery 在一次选择中使用多种方法的能力。我使选择变得简单(因此很慢),以便更加关注这项技术。
    • 虽然避免重复搜索 DOM 是一件好事——最后一个例子是一个不可读的混乱,我不知道发生了什么。如果您计划多次使用 fetch 的结果,请将其存储在变量中。它使代码更易于维护。
    【解决方案13】:

    始终将 $(this) 缓存到有意义的变量中 特别是在 .each()

    这样

    $(selector).each(function () {
        var eachOf_X_loop = $(this); 
    })
    

    【讨论】:

    • 如果您懒得想一个好的变量名,请使用$self$this
    【解决方案14】:

    类似于 Repo Man 所说的,但不完全一样。

    在开发 ASP.NET winforms 时,我经常这样做

    $('<%= Label1.ClientID %>');
    

    忘记#号。正确的形式是

    $('#<%= Label1.ClientID %>');
    

    【讨论】:

      【解决方案15】:

      活动

      $("selector").html($("another-selector").html());
      

      不会克隆任何事件 - 您必须重新绑定它们。

      根据 JP 的评论t - 如果您通过 true,clone() 会重新绑定事件。

      【讨论】:

      • Clone() 如果你通过 true。
      • jQuery 1.3.2 中的 live() 怎么样?
      【解决方案16】:

      避免多次创建相同的 jQuery 对象

      //Avoid
      function someFunc(){
         $(this).fadeIn();
         $(this).fadeIn();
      }
      
      //Cache the obj
      function someFunc(){
         var $this = $(this).fadeIn();
         $this.fadeIn();
      }
      

      【讨论】:

      • var $this = $(this).fadeIn();?你正在缓存一个效果?
      • 它返回元素,它称为链接!
      • 你可以同时设置一个变量并对其执行操作吗?
      • 确实如此,但不要相信我的话。试试吧。如果不返回代表元素的 jquery 对象,您认为以下情况如何可能? $('#divId').hide().show().fadeIn()....等
      • 这行得通,但我认为将$this = $(this); 放在单独的行上更具可读性。如果可以(不要弄得一团糟),忘掉$this,把所有东西都串起来:$(this).fadeIn().fadeIn();
      【解决方案17】:

      我对 JavaScript 也这么说,但是 jQuery,JavaScript 永远不应该取代 CSS。

      此外,请确保该网站可供关闭 JavaScript 的人使用(今天的相关性不如过去,但拥有一个完全可用的网站总是很高兴)。

      【讨论】:

        【解决方案18】:

        进行过多的 DOM 操作。虽然 .html()、.append()、.prepend() 等方法很棒,但由于浏览器渲染和重新渲染页面的方式,过于频繁地使用它们会导致速度变慢。通常最好将 html 创建为字符串,并将其包含到 DOM 中一次,而不是多次更改 DOM。

        代替:

        var $parent = $('#parent');
        var iterations = 10;
        
        for (var i = 0; i < iterations; i++){
            var $div = $('<div class="foo-' + i + '" />');
            $parent.append($div);
        }
        

        试试这个:

        var $parent = $('#parent');
        var iterations = 10;
        var html = '';
        
        for (var i = 0; i < iterations; i++){
            html += '<div class="foo-' + i + '"></div>';
        }
        
        $parent.append(html);
        

        甚至这个 ($wrapper 是一个新创建的元素,它还没有被注入到 DOM 中。将节点附加到这个包装器 div 不会导致减速,最后我们将 $wrapper 附加到 $parent,仅使用一个 DOM 操作):

        var $parent = $('#parent');
        var $wrapper = $('<div class="wrapper" />');
        var iterations = 10;
        
        for (var i = 0; i < iterations; i++){
            var $div = $('<div class="foo-' + i + '" />');
            $wrapper.append($div);
        }
        
        $parent.append($wrapper);
        

        【讨论】:

        • +1... 我每秒都在多个元素上使用 .html() 。注意到它确实开始减慢一切!
        【解决方案19】:

        在 ASP.NET 项目中使用 ClientID 获取控件的“真实”ID。

        jQuery('#<%=myLabel.ClientID%>');
        

        此外,如果您在 SharePoint 中使用 jQuery,则必须调用 jQuery.noConflict()。

        【讨论】:

        • ?这是一个怎样的陷阱?这是 ASP.NET 行为的解决方法。
        • 是的。这不是一个 jQuery 问题。这是asp.net webforms的错误。
        • 同意。但无论如何,在 ASP.NET 中使用 jQuery 时,您都需要注意这一点。
        • OP 没有提到 asp.net
        【解决方案20】:

        向函数传递 ID 而不是 jQuery 对象:

        myFunc = function(id) { // wrong!
            var selector = $("#" + id);
            selector.doStuff();
        }
        
        myFunc("someId");
        

        传递一个包装的集合要灵活得多:

        myFunc = function(elements) {
            elements.doStuff();
        }
        
        myFunc($("#someId")); // or myFunc($(".someClass")); etc.
        

        【讨论】:

          【解决方案21】:

          过度使用链接。

          看这个:

          this.buttonNext[n ? 'bind' : 'unbind'](this.options.buttonNextEvent, this.funcNext)[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);
          

          Explanation

          【讨论】:

          • 看起来很有趣,这是一种混淆。
          • 链接(单独)很难“过度”使用。看起来该代码过度使用了 javascript 三元运算符。请参阅en.wikipedia.org/wiki/Ternary_operation#JavaScript 了解更多信息。
          • 很高兴我不必维护您的代码。
          【解决方案22】:

          使用字符串累加器样式

          使用 + 运算符在内存中创建一个新字符串,并将连接的值分配给它。只有在此之后,才会将结果分配给变量。 为了避免连接结果的中间变量,您可以使用 += 运算符直接分配结果。 慢:

          a += 'x' + 'y';
          

          更快:

          a += 'x';
          a += 'y';
          

          原始操作可以比函数调用更快

          考虑在性能关键的循环和函数中对函数调用使用替代的原始操作。 慢:

          var min = Math.min(a, b);
          arr.push(val);
          

          更快:

          var min = a < b ? a : b;
          arr[arr.length] = val;
          

          阅读更多JavaScript Performance Best Practices

          【讨论】:

            【解决方案23】:

            如果您希望用户在浏览器中看到 html 实体,请使用 'html' 而不是 'text' 来注入 Unicode 字符串,例如:

            $('p').html("Your Unicode string")
            

            【讨论】:

              【解决方案24】:

              我的两分钱)

              通常,使用 jquery 意味着您不必一直担心 DOM 元素的实际情况。你可以写这样的东西——$('div.mine').addClass('someClass').bind('click', function(){alert('lalala')})——这段代码将执行而不会抛出任何错误。

              在某些情况下,这很有用,在某些情况下 - 根本没有,但事实上 jquery 往往是对空匹配友好的。然而,replaceWith 会在尝试将它与不属于文档的元素一起使用时抛出错误。我觉得这很违反直觉。

              在我看来,另一个陷阱是 prevAll() 方法返回的节点顺序 - $('&lt;div&gt;&lt;span class="A"/&gt;&lt;span class="B"/&gt;&lt;span class="C"/&gt;&lt;span class="D"/&gt;&lt;/div&gt;').find('span:last-child').prevAll()。其实没什么大不了的,但我们应该记住这个事实。

              【讨论】:

                【解决方案25】:

                如果您打算在大量数据中进行 Ajax,例如,一个包含 20 列的表的 1500 行,那么甚至不要考虑使用 jQuery 将这些数据插入到您的 HTML 中。使用纯 JavaScript。 jQuery 在较慢的机器上会太慢。

                另外,jQuery 有一半的时间会做一些会导致它变慢的事情,比如尝试解析传入 HTML 中的脚本标签,以及处理浏览器的怪癖。如果您想要快速插入速度,请坚持使用纯 JavaScript。

                【讨论】:

                • -1 .html() 函数与原生方法一样快
                • 每个反对我的人显然都没有尝试在 IE 上插入大量 DOM 并观察事情变得缓慢。 jquery 速度慢的原因是它不会简单地插入 dom,它还会做一些其他事情,比如检查 dom 是否有脚本,如果它在 IE 中则执行它们,以及其他一些你不需要做的事情,如果你知道的话你要插入什么样的数据
                • 只要您不需要担心浏览器泄漏等问题,.innerHTML 就可以。但是,如果您正在构建像 Gmail 这样的用户保持标签打开数小时的东西,您将不得不硬着头皮处理额外的缓慢问题。对于好奇的人,这正是 jQuery 的 .html() 所做的:james.padolsey.com/jquery/#v=1.4&fn=jQuery.fn.html
                【解决方案26】:

                在一个小项目中使用 jQuery,只需几行普通 JavaScript 即可完成。

                【讨论】:

                • 我不介意被改装,但请论证您的选择。
                • -1 jQuery 抽象了一个损坏的 API。这样,您始终可以确保您的代码正常工作。假设您使用 jQuery 编写了一些代码,并且在新版本中引入了一些随机浏览器错误——您需要做的就是导入 jQuery 框架的更新版本。与必须弄清楚如何自己解决错误相比。
                • +1 对我来说似乎是合理的——如果你只使用几行代码,那么使用 vanilla JS 是有意义的。
                • @roosteronacid,你的论点没有抓住重点。浏览器不太可能在复杂度较低的脚本中引入回归,或者为此处理跨浏览器问题。两年前,我一直在使用 mootools,在某种情况下它无法读取 IE 上的元素内容。经过几个小时的努力找出问题所在,我只是用纯 js 重写了该部分。因此,由于浏览器升级,jQuery 更容易崩溃,而不是普通的 javascript。我每天都会自己解决一个错误,而不是破解库代码。
                • couple of lines of ordinary JavaScript 当然没问题。但是什么时候会这样呢?人们说“为什么不使用 vanilla javascript??”还没有被 IE 咬得够呛……更不用说你必须编写多少杂乱无章的样板代码才能在普通的旧 JS 中做简单的事情。
                【解决方案27】:

                不理解事件绑定。 JavaScript 和 jQuery 的工作方式不同。

                根据大众需求,举个例子:

                在 jQuery 中:

                $("#someLink").click(function(){//do something});
                

                没有 jQuery:

                <a id="someLink" href="page.html" onClick="SomeClickFunction(this)">Link</a>
                <script type="text/javascript">
                SomeClickFunction(item){
                    //do something
                }
                </script>
                

                基本上不再需要 JavaScript 所需的钩子。 IE。使用内联标记(onClick 等),因为您可以简单地使用开发人员通常用于 CSS 目的的 ID 和类。

                【讨论】:

                • 想详细说明一下?最好举个例子?
                • JavaScript 不提供 addEventListener() 和 attachEvent() 来执行此操作吗?
                • 关注点分离,伙计。保持 HTML 和 JS 分开
                猜你喜欢
                • 1970-01-01
                • 2015-04-08
                • 1970-01-01
                • 2010-09-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-09-14
                相关资源
                最近更新 更多