APIdevise和jQuery

我经常听说jQuery做出了一些糟糕的API决策。 尽pipejQuery并不是我最喜欢的库,但它是我经常使用的库,我很难指出APIdevise中的具体错误,以及如何改进。

jQuery API的哪些部分可以做得更好, 怎样才能实现不同, 为什么不同的实现会更好?

这个问题扩展到API的低级别的个别细节和API的高级细节 。 我们只是在讨论API中的缺陷,而不是在库的高层devise/目的中的缺陷,jQuery仍然是一个以select器引擎为中心的DOM操作库。

由于stream行库中API冻结的必要性,jQuery陷入了当前状态,开发人员做得很好。 从最近的.attr.prop变化可以看出,开发人员没有灵活性来改变他们的任何devise决定(这是一个耻辱!)。

我能想到的一个具体例子就是

$.each(function(key, val) { })

VS

$.grep(function(val, key) { })

这足以让我感到困惑,所以我必须仔细检查参数是多频繁的。

请不要将jQuery 与dojo和YUI等完整的框架进行比较,并抱怨缺lessfunction。

  • .load()被重载完全不同的行为取决于传递的参数

  • .toggle()被重载完全不同的行为取决于传递的参数

  • jQuery()函数的重载可能太多了。

  • 你提到的.attr() 。 与物业的区别应该是国际海事组织。

  • .map( key,val )$.map( val,key ) ,而this值是不同的。

  • 非标准select器应该被保留在Sizzle IMO之外。 基于JavaScript的select器引擎应该在多年后变得过时了,而那些对专有select器感兴趣的人将会有一个更加困难的转换

  • .closest().live()等方法命名方法不佳。 他们究竟做了什么?

  • 我最近发现,在创build一个新的元素时,你不能通过props参数设置标准的widthheight属性。 jQuery运行它自己的widthheight方法。 国际海事组织,规格属性应该被优先考虑,特别是因为widthheight可以通过css设置。

 $('<img/>', { css:{width:100, height:100}, width:100, // <-- calls method, why? height:100, // <-- calls method, why? }); 
  • $.get().get()完全不同。

  • .get().toArray()在传递参数时是相同的

  • toArray()$.makeArray()有效地做同样的事情。 为什么不给他们像.each()$.each()

  • 两种不同的事件委托方法。 .delegate()是明智的,而.live()是神奇的“哇,它只是起作用!” 一。

  • .index()被重载了3个行为,但是它们的区别可能会令人困惑

  // v---get index v---from collection (siblings is implied) $('selector').index(); // v---from collection v---get index $('selector').index(element); // v---get index v---from collection $('selector').index('selector'); 

第一个是可以理解的,如果你记得它只在第一个元素上运行

第二个是最有意义的,因为jQuery方法通常在整个集合上运行。

第三个是完全混淆的。 该方法不会指示哪个select器是集合,哪个select器表示要从集合索引的元素。

为什么不消灭第三个,让人们使用第二个这样的:

  // v---from collection v---get index $('selector').index( $('selector') ); 

这种方式更适合jQuery的其余部分.index()在整个集合上运行。

或者至less逆转select器的含义以更好地适应:

  // v---from collection v---get index $('selector').index('selector'); 

无论如何,这是另一个想法。

我对jQuery的事件处理/数据存储系统有一些担忧。 它被称赞,因为它没有添加function的on[event]属性,可以closures其他元素,在IE中创build内存泄漏。 相反,它放置了一个轻量级的expando属性,该属性映射到jQuery.cache的条目,该条目包含处理程序和其他数据。

我相信它会附加一个处理程序,然后调用您分配的处理程序。 或类似的东西。

无论系统是什么并不重要。 重点是元素和jQuery.cache之间的连接就是expando。

为什么这是一个大问题? 从哲学上讲,jQuery不是一个框架, 这是一个图书馆。 看来,作为一个图书馆,你应该能够使用或不使用jQuery的function,而不用担心负面影响。 然而,如果您从DOM中移除元素之外的时候去了jQuery之外,那么您通过expando孤立了与这些元素相关联的任何处理程序和其他数据,从而创build了一个很好且完全跨浏览器的内存泄漏。

例如,像el.innerHTML = ''这样简单的东西可能是非常危险的。

加上jQuery.noConflict()function。 这使得开发人员可以将jQuery与使用$全局名称空间的其他库一起使用。 那么如果其中一个库删除了一些元素呢? 同样的问题。 我有一种感觉,开发人员需要像使用Prototypejs这样的库来连接jQuery,可能并不知道足够的JavaScript来做出好的devise决策,并且会遇到像我所描述的那样的问题。


就我所知的图书馆哲学思想的改进而言,他们的哲学是“多做,less写”或者什么的。 我认为他们很好地完成了。 你可以写一些非常简洁而富有performance力的代码来完成大量的工作。

虽然这是非常好的,但在某种程度上,我认为这是一个负面的东西。 你可以这么做,很容易,初学者很容易写一些非常糟糕的代码。 如果有一个“开发人员构build”logging了滥用图书馆的警告,那么这将是一件好事。

一个常见的例子是在一个循环中运行一个select器。 DOMselect非常容易,即使您只是运行该select器,您似乎也可以在每次需要元素时运行select器。 我认为一个改进是jQuery()函数loggingselect器的重复使用,并给出一个控制台注意select器可以被caching。

因为jQuery是如此占统治地位,所以我认为如果他们不仅使得成为JavaScript / DOM程序员变得容易,而且帮助你成为更好的人,那将是一件好事。

jQuery处理集合与单个元素的方式可能会令人困惑。

说如果我们要更新一些元素的CSS属性,我们可以写,

 $('p').css('background-color', 'blue'); 

setter将更新所有匹配元素的背景颜色。 但是,获取器假定您只想检索第一个元素的值。

 $('p').css('background-color') 

MooTools将返回一个包含每个匹配元素的背景颜色的数组,这看起来更直观。

jQuery的命名约定提高了简洁性而不是清晰度。 我喜欢苹果的命名策略:

清楚而不是简单。

下面是Objective-C中可变数组类( NSMutableArray )的方法名称示例。

 removeObjectAtIndex:(..) 

这并不是要聪明地去掉那些被删除或删除的东西。 您需要知道的所有信息都包含在方法的名称中。 将其与大部分jQuery方法(如afterinsertAfter

如果有人可以直观地理解afterinsertAfter做什么而不读取文档或源代码,那么这个人就是一个天才。 不幸的是,我不是一个 – 也是迄今为止,我仍然需要去查阅文档来弄清楚在使用这两种方法的时候到底在哪里。

包含在jquery中:

 .post() .get() .getScript() .getJSON() .load() 

不在jQuery中:

 $.getXML(); $.headXML(); $.postXML(); $.putXML(); $.traceXML(); $.deleteXML(); $.connectXML(); $.getJSON(); $.headJSON(); $.postJSON(); $.putJSON(); $.traceJSON(); $.deleteJSON(); $.connectJSON(); $.headScript(); $.postScript(); $.putScript(); $.traceScript(); $.deleteScript(); $.connectScript(); $.getHTML(); $.headHTML(); $.postHTML(); $.putHTML(); $.traceHTML(); $.deleteHTML(); $.connectHTML(); $.getText(); $.headText(); $.postText(); $.putText(); $.traceText(); $.deleteText(); $.connectText(); $.head(); $.put(); $.trace(); $.delete(); $.connect(); 

为什么这会打扰我? 不是因为我们在图书馆没有上面的方法,这只是愚蠢的,我恨,如果我们曾经做过(加上,大多数不会与浏览器工作),但我讨厌的是这些简短的方法遍布这个地方: $.post(); 通过邮件发送ajax请求。

知道什么涵盖了这个列表中的所有内容? 这个function不是简单的, $.ajax ,它是全function的,可以覆盖所有的东西,甚至可以configuration它来存储默认值,实质上就是创build所有这些短手。 你可以创build你自己的方法,如果你想打电话给ajax(这是所有这些)。

这是真正令人讨厌的地方。

有人用简写的方式写下所有的代码:

 $.getJSON( 'ajax/test.html', function(data) { $('.result').html(data); } ); 

好的,等等,我们想把它改成我们从post中得到的XML feed,也是我们需要在post之前和之后做一些事情。 哦,让我们切换到非简短的方法

 $.ajax({ type: 'POST', url: url, data: data, success: success dataType: dataType }); 

哦,等等,我不能只replace这个词,整个结构都到处都是。

这个,特别是对于像.load()这样的东西,为了说明为什么PHP有这样一个令人讨厌的API,他们正在尝试去做他们不应该做的事情。

为了扩展AJAX调用,请查看animation部分。 我们已经调用了slideUp,slideDown,fadeIn,fadeOut,fadeToggle,显示和隐藏。 为什么? 我的幻灯片在哪里离开,向右滑动,滑入,滑出,传送以及其他所有我们能想到的事情? 为什么不坚持$ .animate(),并让别人写一个插件,如果我们想要这些效果。 事实上,有人写了一个插件,jQueryUI扩展了animation。 这太疯狂了,导致人们不知道某些效果会在他们的div上创buildCSS规则,最终导致他们以后想要做的事情。

保持纯净,保持简单。

帕特里克·道夫在他的(奇妙的)答案中打出了大部分的观点。 只需要添加一些其他的例子来添加他的collections。

API应该是一致的; jQuery在很多领域都取得了成功(正如许多情况下所期望的那样,jQuery对象/获取值的返回非常一致)。 然而在其他情况下,情况并不理想。

方法名称帕特里克已经指出, 最接近()是一个废话的方法名称。 prev()和next()看起来就像prevAll()和nextAll()实际提供的那样。

delay()让很多人困惑:在下面的例子中,你期望发生什么? ( 究竟发生了什么? )

 $('#foo').hide().delay(2000).slideDown().text('Hello!').delay(2000).hide(); 

方法参数许多树遍历函数与它们接受的内容不一致, 他们都接受select器,jQuery对象和元素的混合,但没有一个是一致的; 考虑到他们都做类似的工作,这是不好的。 查看最近的() , find() , siblings() , parents() , parent()并比较差异!

在内部,jQuery的“核心”原本包含了许多相互交织的方法,开发团队在过去的版本中努力分裂(并且做得很好)。 像css,属性,操作和遍历等内部模块都被捆绑在一个大的包里。