避免jQuery陷阱[关闭]


210

我正在用jQuery启动一个项目。

您在jQuery项目中遇到了哪些陷阱/错误/误解/滥用/误用?


4
这应该不是已经关闭了是“没有建设性”。已经出现了一些非常有用的答案,并且该问题已被评注220次。如果您有足够的业力,请投票重新开放。
罗伊·普林斯

在我看来,jQuery本身就是一个陷阱
gromit190

Answers:


189

不了解性能影响并过度使用选择器,而不是将选择器分配给局部变量。例如:-

$('#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');
});

或者甚至更好地链接: -

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

当我意识到调用堆栈是如何工作时,我发现了这一启发性时刻。

编辑:纳入建议的评论。


16
youtube链接+1。我学到了很多东西。
杰森

23
我认为将内容分配给局部变量很棒,但是不要忘记链接的功能(从您的示例中得出):$(“#label”)。method()。method2()。css(“ background-color”,“红”);
Lance McNearney 09年

YouTube影片很棒。我看过其他有关该主题的Google演示文稿,但我仍然学到了一些东西!谢谢!
加布里埃尔·赫尔利

链接也+1,非常好!
乔什·斯托多拉

7
在jQuery上下文中对变量使用美元符号是一种惯例。所以你可能想写var $label = $('#label');
TimBüthe,2010年

90

了解如何使用上下文。通常,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);

9
啊!好吧,这大约是我修复的错误中的1,000,000。+1
jammus 2009年


1
感谢您指出这个JP。现在,该怎么办...我应该删除我的答案,以便没有其他人疯狂地改变他们的代码吗?
slolife

不,从优化角度来看,这仍然是一个好主意。:)
詹姆斯

2
jQuery检查上下文是否是jQuery的实例,因此没有理由[0]$('.myClass', ct);或者,如果您知道ct是jQuery的实例,则可以使用findct.find(".myClass")
gradbot

62

不要使用裸类选择器,例如:

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

最后将查看每个元素,以查看其是否具有“按钮”类。

相反,您可以提供帮助,例如:

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

我去年从Rebecca Murphy的博客中学到了

更新 -这个答案是2年前给出的,对于当前版本的jQuery 不正确。评论之一包括测试以证明这一点。还有一个测试更新版本,其中包含此回答时的jQuery版本。


6
我也有相反的印象。也许在没有实现getElementsByClassName的浏览器中就是这种情况,但是否则,您只是给jQuery做更多的工作。我非常希望看到Rebecca发布一些基准测试:)
Alex Barrett,

7
您正在减少要做的工作量。这就像告诉某人将袜子从梳妆台的抽屉中取出,而不是告诉他们将袜子从房间中取出。减少其必须执行的“外观”量。
偷偷摸摸的

4
当您编写CSS(至少包括element标记)时,情况正好相反。见code.google.com/speed/page-speed/docs/...
kmiyashiro

7
@偷偷摸摸并非所有事物都能真实地模拟现实生活。例如,如果浏览器支持它,则$('.b')可以使用document.getElementsByClassName('b')它,但是这样做$('a.b')会使它获取具有类的所有匹配元素,b然后确认它们是两阶段操作中的锚。后者听起来对我来说需要更多工作。对于现实生活中的类比,请尝试以下操作:查找我房间里的所有袜子。现在,扔掉不在我梳妆台中的那些。
Alex

2
我相信对选择器的误解是由于以下事实:在旧版本的jquery中,执行$('#foo')比执行$('div#foo')更快,因为根据定义,id是唯一的。我很确定这在以后的版本中已得到解决,但是该建议仅适用于ID,不适用于其他类型的选择器
Alex Heyd

35

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

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

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

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

19
我认为这大致适用于将同步(内联)代码分解为命名函数的程度。如果您有一大堆要求提供名称的代码,那就继续吧。但是不要仅仅因为将代码包装在一个函数中就将代码移到了行外。匿名函数的存在是有充分理由的。
丹·布雷斯劳

4
实际上,我喜欢给函数起“名字”。当您调试代码时,它会看到正确命名的函数,而不是看到无数的匿名函数列表,这非常有用。
解决方案

1
您的观点是正确的,而我本人可能已经被它绊倒了几次。即使这样,“ 大致相同的程度”仍然对我有用。
丹·布雷斯劳

1
尤其是 如果绑定是循环发生的!
daniellmb

调试时,命名函数也会为您带来极大的好处。没有什么比看8级深的调用栈更糟了(anonymous)。在此处阅读有关此提示的更多信息:stackoverflow.com/questions/182630/jquery-tips-and-tricks/…–

34
  • 避免滥用文件准备就绪。
  • 使文档准备好仅用于初始化代码。
  • 始终在准备好的文档外部提取函数,以便可以重复使用它们。

我已经在doc ready语句中看到了数百行代码。丑陋,无法读取且无法维护。


6
+1。通常,我见过的大多数jQuery代码都使用数百行的函数。我不知道为什么“ jQuery开发人员”不喜欢使用较小的功能。
SolutionYogi

6
@SolutionYogi,因为大多数只是JS新手?
adamJLev 2010年

我不准备在文档中准备很长的功能,这是一个很好的建议。但是,从尚未准备好文档的总体功能中运行许多小组件功能并不一定是最佳实践。如果总体功能是唯一使用这些代码段的功能,那么即使很难阅读,也最好将其全部放在一个功能中。调用函数会产生大量开销,如果仅在一个上下文中使用代码,则应避免这种情况。
sage88

34

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

而不是complete使用success

请参阅文档中的Ajax事件


1
我在成功与完成之间来回走动,您能否解释为什么您认为完成更好?
尼尔N

1
我并不是说完整更好。我要说的是,您需要避免误导complete的使用,而应该使用成功才能处理响应数据。
Artem Barger

2
好吧,它总是被调用。但是我不同意。完成是隐藏加载gif等的最佳方法。当然,应该使用成功来处理响应,并使用错误来处理任何错误。
redsquare

1
他建议使用成功而不是完成。当ajax请求为“ complete”时,总是会触发“ complete”,无论它是成功完成还是失败。
SolutionYogi

@redsquare,您能否完全不同意这一点?我指的是数据处理,并且不介意使用完整的处理程序隐藏/显示您拥有的任何图片的机会。
Artem Barger 2009年

24

带回调的“连锁”动画事件。

假设您想动画一个段落,使其消失。您还希望随后从DOM中删除该元素。您可能认为您可以简单地链接方法:

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

在此示例中,将在.fadeOut()完成之前调用.remove(),这会破坏渐变效果,并简单地使该元素立即消失。相反,当您只想在完成前一个命令时才发出命令时,请使用回调函数:

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

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


24

如果您多次绑定同一事件,它将触发多次。我通常总是unbind('click').bind('click')为了安全起见


2
这不是特定于jQuery,但要记住重要的事情。
SolutionYogi

11
您可以使用实时事件来不必将同一事件绑定两次。
Powerlord

如果使用过多,live会有其自身的(性能)问题。在1.3.3中可以提供上下文的更好。
redsquare

23

不要滥用插件。

在大多数情况下,您只需要库,甚至可能需要用户界面。如果保持简单,则从长远来看,您的代码将是可维护的。并非所有插件均受支持和维护,实际上大多数插件均不受支持。如果可以使用核心元素模拟功能,则强烈建议您使用。

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

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


2
网格呢?你自己做?
jmav

是。从项目到项目的数据以各种方式出现。我更希望完全控制实现该网格只会帮助我达到中等水平,然后我必须即兴创作。
Elzo Valugi 09年

如果{给了足够的时间,通常我宁愿直接编写所有数据驱动的dom(management)(css / html)代码。换句话说-不要将数据传递给“插件”,并且将其喷出html。很难评估插件的(中间域)当前范围的兼容性,而不必考虑未来的需求。认为...设计师,规划师,经理,经理,经理。哦,还有客户和用户。但是如果您拥有所有这些东西,那么您将没有足够的“时间”。因此,只需已经使用jqgrid-您就浪费了时间。还完成了吗?}
user406905 2010年

22

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

如果您发现要遍历jQuery``.each''方法来遍历DOM元素,请问自己是否可以使用选择器来获取元素。

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

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

Firebug实际上是用于这种调试的。如果您打算使用Javascript来破坏DOM,则需要像Firebug这样的好工具来提供可见性。

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

其他很棒的主意在此多态播客中: (jQuery秘密与Dave Ward) http://polymorphicpodcast.com/shows/jquery/


1
我已经做了很多次了。您只需要记住,大多数jQuery函数将对选择器返回的所有元素进行操作。
DisgruntledGoat

不喜欢诚实地使用.each方法-Simon
Hayter

14

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

$( "#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
+1比jQuery问题更多的是JavaScript问题,但我以前经常为此而烦恼。
mmacaulay

13

避免多次搜索整个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();

2
$(“。aclass”)。this()。that(); 不好!全班唯一的选择者很慢
redsquare

这是一个说明性示例,显示了Jquery在一个选择上使用多种方法的能力。我将选择变得简单(因此很慢),以更加关注此技术。
googletorp,2009年

10
虽然避免重复搜索DOM是一件好事-最后一个例子是一个无法理解的混乱,我不知道发生了什么。如果您打算多次使用提取结果,请将其存储在变量中。它使代码更具可维护性。
昆汀,2009年

12

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

像这样

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

12
如果您懒得想一个好的变量名,请使用$self$this
gradbot

10

类似于Repo Man所说的,但不完全相同。

在开发ASP.NET Winforms时,我经常做

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

忘记#号。正确的形式是

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

10

大事记

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

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

根据JP的命令,如果传递true,则clone()会重新绑定事件。


4
如果您传递true,则Clone()会执行。
詹姆斯

jQuery 1.3.2中的live()怎么样?
jmav

9

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

//Avoid
function someFunc(){
   $(this).fadeIn();
   $(this).fadeIn();
}

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

var $ this = $(this).fadeIn();? 您正在缓存效果吗?
杰森

12
它返回元素,称为链!
redsquare

您可以设置一个变量并同时对其执行操作?
杰森

1
确实,但是不要相信我。试试吧。如果未返回表示元素的jquery对象,您如何看待以下内容?$('#divId')。hide()。show()。fadeIn().... etc
redsquare 2009年

14
那行得通,但我认为将其$this = $(this);放在单独的行中更具可读性。如果可以(不要弄得一团糟),那就别管了,而把$this所有东西都$(this).fadeIn().fadeIn();
拴在一起

8

我也对JavaScript说过这一点,但对于jQuery,JavaScript绝不能取代CSS。

另外,请确保该网站可用于关闭了JavaScript的用户(今天不像以前那样重要,但总是很高兴拥有一个完全可用的网站)。


6

进行过多的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的新创建的元素。将节点添加到该wrapper div不会导致性能下降,最后我们仅使用一个DOM操作就将$ wrapper附加到$ parent上):

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()。注意它确实开始放慢一切!
User2 2014年

5

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

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

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


11
?这是一个陷阱吗?这是ASP.NET行为的解决方法。
SolutionYogi

1
是的 这不是jQuery问题。这是asp.net网络表单的错误。
redsquare

3
同意 但是,无论如何,在ASP.NET中使用jQuery时都需要注意这一点。
Jacobs Data Solutions

2
OP没有提到asp.net
Redsquare

4

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

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

myFunc("someId");

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

myFunc = function(elements) {
    elements.doStuff();
}

myFunc($("#someId")); // or myFunc($(".someClass")); etc.

3

过多使用链接。

看到这个:

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

说明


1
看起来很有趣,有点让人困惑。
Dykam,

6
链接(单独使用)很难“过量使用”。看起来该代码过度使用了javascript三元运算符。有关更多信息,请参见 en.wikipedia.org/wiki/Ternary_operation#JavaScript
丹·埃斯帕萨

3
我很高兴不必维护您的代码。
cdmckay

3

使用字符串累加器样式

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

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上阅读更多内容


1

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

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

1

我的两分钱)

通常,使用jquery意味着您不必一直担心实际的DOM元素。您可以编写这样的内容$('div.mine').addClass('someClass').bind('click', function(){alert('lalala')})--并且此代码将执行而不会引发任何错误。

在某些情况下,这很有用,在某些情况下-根本没有用,但这是事实,jquery倾向于友好的空匹配。但是,replaceWith如果尝试将其与不属于文档的元素一起使用将引发错误。我觉得这很违反直觉。

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


0

如果您打算在Ajax中处理大量数据,例如表的1500行有20列,那么甚至不要考虑使用jQuery将数据插入到HTML中。使用纯JavaScript。jQuery在速度较慢的计算机上会太慢。

同样,jQuery有一半的时间会做一些会使其变慢的事情,例如尝试解析传入HTML中的脚本标签,并处理浏览器的怪癖。如果要提高插入速度,请坚持使用纯JavaScript。


1
-1 .html()函数的速度与本机方法一样快
cllpse

显然,每个挫败我的人都没有尝试在IE上插入大量的DOM,然后看事情变慢了。jQuery之所以缓慢是因为它不会简单地插入dom,它还会执行其他一些操作,例如检查dom是否具有脚本,并在IE中执行该脚本,并执行其他一些操作(如果您确切知道的话)您要插入哪种数据
mkoryak 2010年

1
只要您不必担心浏览器泄漏之类的问题,.innerHTML都可以。但是,如果您要构建类似Gmail的用户将标签页保持打开状态数小时的功能,那么您将不得不硬着头皮应对额外的速度。出于好奇,这正是jQuery的.html()作用:james.padolsey.com/jquery/#v=1.4&fn=jQuery.fn.html
adamJLev 2010年

-1

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


我不介意被淘汰,但请提出您的选择。
老虎钳

8
-1 jQuery抽象了一个损坏的API。这样,您始终可以确保您的代码正常工作。假设您已经使用jQuery编写了一些代码,并随新版本引入了一些随机的浏览器错误-您要做的就是导入jQuery框架的更新版本。相对于必须弄清楚如何自己解决该错误。
cllpse

+1对我来说似乎很合理-如果您仅使用几行内容,则仅使用普通JS就有意义。
亚历克斯

1
@roosteronacid,您的论点有误。对于浏览器来说,不太可能在复杂程度较低的脚本中引入回归,或者解决跨浏览器问题。两年前,我正在使用mootools,在某些情况下,它无法读取IE上的元素内容。经过数小时的努力以找出问题后,我只用纯js重写了该部分。因此,实际上,由于浏览器升级,jQuery更有可能崩溃而不是普通的javascript失败。我会每天解决自己的错误,而不是通过库代码来破解。
老虎钳

3
couple of lines of ordinary JavaScript好没问题。但是,什么时候可以呢?人们说“为什么不使用香草javascript?” IE尚未给您足够的努力……更不用说您必须编写多少粗俗的代码才能在普通的旧JS中做简单的事情。
adamJLev

-3

不了解事件绑定。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不再需要钩子。即使用内联标记(onClick等),因为您可以简单地使用开发人员通常用于CSS用途的ID和类。


5
关心详细吗?最好是一个例子吗?
SolutionYogi

7
JavaScript是否不提供addEventListener()和attachEvent()来做到这一点?
亚历克斯

2
关注点分离,伙计。保持你的HTML和JS分离
唐·
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.