API设计和jQuery

Ray*_*nos 43 javascript api jquery api-design

我经常听说jQuery做出了一些糟糕的API决策.虽然jQuery不是我最喜欢的库,但它是我经常使用的库,我发现很难指出API设计中的具体错误或者如何改进它.

jQuery的API的哪些部分可以做得更好,它如何实现不同,为什么不同的实现会更好?

问题扩展到API的低级别个别详细信息和API的高级详细信息.我们只讨论API中的缺陷而不是库的高级设计/目的中的缺陷,jQuery仍然是以选择器引擎为中心的DOM操作库.

由于在流行的库中需要API冻结,jQuery仍处于当前状态并且开发人员做得很好.从最近的.attrvs .prop变化可以看出,开发人员没有灵活性来改变他们的任何设计决策(这是一种耻辱!).

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

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

VS

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

令人困惑的是,我必须仔细检查频繁的参数.

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

use*_*716 40

  • .load() 根据传递的参数重载完全不同的行为

  • .toggle() 根据传递的参数重载完全不同的行为

  • jQuery()也许是过多的函数重载.

  • .attr()你提到的.与属性的区别应该是立即IMO.

  • .map( key,val )但是$.map( val,key ),this价值观是不同的.

  • 非标准的选择者应该被排除在Sizzle IMO之外.基于Javascript的选择器引擎应该在很多年内变得过时,而专注于选择器的人将会遇到更困难的转换

  • 差的方法命名方法,如.closest().live().他们究竟做了什么?

  • 我最近发现在创建新元素时,无法通过参数设置标准widthheight属性props.jQuery的运行自身widthheight方法来代替.IMO,规范的属性应该被优先考虑,特别是因为widthheight可以通过设置css.

$('<img/>', { 
    css:{width:100, height:100},
    width:100, // <-- calls method, why?
    height:100, // <-- calls method, why?
});
Run Code Online (Sandbox Code Playgroud)
  • $.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');
Run Code Online (Sandbox Code Playgroud)

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

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

第三个完全令人困惑.该方法不指示哪个选择器是集合,哪个选择器表示您希望从集合中获取索引的元素.

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

 // v---from collection      v---get index
$('selector').index( $('selector') );
Run Code Online (Sandbox Code Playgroud)

这样,它更适合与.index()整个集合上运行的jQuery的其余部分.

或者至少颠倒选择器的含义以更好地适应:

 // v---from collection   v---get index
$('selector').index('selector');
Run Code Online (Sandbox Code Playgroud)

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

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

我相信它会附加一个处理程序,然后调用你指定的处理程序.或类似的东西.

无论系统是什么都不重要.关键是元素和它之间的连接jQuery.cache是expando.

为什么这是一个大问题?哲学上,jQuery不是一个框架; 这是一个图书馆.看起来作为一个库你应该能够使用或不使用jQuery函数而不用担心负面影响.然而,如果你在从DOM中删除元素时转到jQuery之外,你就会通过expando孤立任何处理程序和与这些元素相关的其他数据,从而创建一个漂亮且完全跨浏览器的内存泄漏.

因此,例如,一些简单的事情el.innerHTML = ''可能非常危险.

将此与此jQuery.noConflict()功能结合使用.这使开发人员可以将jQuery与其他利用$全局命名空间的库一起使用.那么如果其中一个库删除了一些元素呢?同样的问题.我有一种感觉,那些需要使用类似PrototypejsjQuery 的库的开发人员可能不知道足够的JavaScript来做出好的设计决策,并且会遇到我所描述的问题.


至于图书馆的预期理念的改进,据我所知,他们的哲学是"多做,少写"等.我认为他们做得很好.您可以编写一些非常简洁但富有表现力的代码,这些代码将完成大量工作.

虽然这是非常好的,但在某种程度上我认为它是负面的.你可以这么做,很容易,初学者很容易写一些非常糟糕的代码.如果有一个"开发人员构建"记录了滥用库的警告,那我觉得很好.

一个常见的例子是在循环中运行选择器.DOM选择很容易做到,你似乎只要每次需要一个元素就可以运行一个选择器,即使你只是运行那个选择器.我认为一个改进是jQuery()记录选择器的重复使用的函数,并给控制台注意可以缓存选择器.

因为jQuery是如此占主导地位,我认为如果他们不仅能够轻松成为一名JavaScript/DOM程序员,而且还能帮助你成为更好的程序员,那将是一件好事.


Anu*_*rag 8

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

假如我们要更新元素集合上的某些css属性,我们可以写,

$('p').css('background-color', 'blue');
Run Code Online (Sandbox Code Playgroud)

setter将更新所有匹配元素的背景颜色.但是,getter假定您只对检索第一个元素的值感兴趣.

$('p').css('background-color')
Run Code Online (Sandbox Code Playgroud)

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

jQuery 的命名约定提升了简洁性而不是清晰度.我喜欢Apple在命名方面的策略:

最好是清楚而不是简短.

NSMutableArray是Objective-C中可变数组class()的方法名称示例.

removeObjectAtIndex:(..)
Run Code Online (Sandbox Code Playgroud)

它并不是想要清除什么被删除或者它被移除的地方.您需要知道的所有信息都包含在方法的名称中.与大多数jQuery的方法相比,这afterinsertAfter.

如果有人可以直观地弄清楚在没有阅读文档或源代码的情况下做什么afterinsertAfter做什么,那么那个人就是天才.不幸的是,我不是一个 - 而且到目前为止,我仍然需要去文档来弄清楚在使用这两种方法时会发生什么.


Mat*_*att 5

patrick dw在他的(精彩)答案中击中了大部分分数.只是添加一些其他示例添加到他的收藏中.

API应该是一致的; 并且jQuery在很多方面都取得了成功(对于返回jQuery对象/获取值非常一致,正如在很多情况下所预期的那样).然而,在其他情况下,它并没有那么好.

方法名称 正如帕特里克已经指出的那样; nearest()是一个废话方法名称.prev()next()似乎最像是在执行prevAll()nextAll()实际提供的工作.

delay()让很多人感到困惑:在下面的例子中,您期望发生哪些事情?(实际发生了什么?)

$('#foo').hide().delay(2000).slideDown().text('Hello!').delay(2000).hide();
Run Code Online (Sandbox Code Playgroud)

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

在内部,jQuery的"核心"本来就包含很多相互交织的方法,使开发团队一直在努力分手了(和做得很好到),在过去的版本.内部模块,如css,属性,操作和遍历都曾经捆绑在同一个大包中.