【问题标题】:API design and jQuery [closed]API设计和jQuery [关闭]
【发布时间】:2011-08-29 03:56:05
【问题描述】:

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

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

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

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

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

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

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

这太令人困惑了,以至于我不得不仔细检查参数的频率。

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

【问题讨论】:

标签: javascript jquery api api-design


【解决方案1】:
  • .load() 被重载,其行为完全不同,具体取决于传递的参数

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

  • jQuery() 函数可能重载过多。

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

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

  • 应该将非标准选择器排除在 Sizzle IMO 之外。基于 Javascript 的选择器引擎应该会在几年内过时,而迷上专有选择器的人将面临更困难的过渡

  • .closest().live() 等方法的方法命名不佳。他们具体是做什么的?

  • 我最近发现,在创建新元素时,不能通过 props 参数设置标准的 widthheight 属性。 jQuery 运行自己的 widthheight 方法。 IMO,规范属性应该被优先考虑,特别是因为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 方法通常对整个集合进行操作。

第三个完全令人困惑。该方法没有指明哪个选择器是集合,哪个选择器代表您想要从集合中获得索引的元素。

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

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

这样,它更适合 jQuery 的其余部分,.index() 对整个集合进行操作。

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

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

不管怎样,还有一个要考虑的。

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

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

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

为什么这很重要?从哲学上讲,jQuery 不是一个框架。这是一个图书馆。看起来,作为一个库,您应该能够使用或不使用 jQuery 函数而不用担心负面影响。然而,如果你在从 DOM 中删除元素时离开 jQuery,你就会通过 expando 孤立任何处理程序和与这些元素相关联的其他数据,从而产生一个很好的完全跨浏览器的内存泄漏。

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

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


就图书馆的预期理念的改进而言,据我所知,他们的理念是“做多,少写”之类的。我认为他们做得很好。您可以编写一些非常简洁但富有表现力的代码来完成大量工作。

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

一个常见的例子是在循环中运行选择器。 DOM 选择很容易做到,看起来你每次需要一个元素时都可以运行一个选择器,即使你只是运行了那个选择器。我认为jQuery() 函数可以记录选择器的重复使用,并在控制台提示可以缓存选择器。

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

【讨论】:

  • map 是我立即想到的。真正奇特的设计决定。
  • 您已经解决了不好的问题,您能否通过 API 改进的重要示例来扩展它。
  • @lonesomeday 这解释了为什么我不知道.map 签名。我以 grep/each 为例,因为至少有一点一致:(
  • @patrick_dw 请告诉我最后一个例子不是真的:(
  • +1 关于使用 expando 属性的突出要点。这是我们谈论 jQuery 与其他库的兼容性时不常谈论的事情。
【解决方案2】:

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

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

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

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

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

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

jQuery 的命名约定 提倡简洁而不是清晰。我喜欢 Apple 的命名策略:

简明扼要。

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

removeObjectAtIndex:(..)

它并不是要聪明地知道要删除的内容或删除的位置。您需要知道的所有信息都包含在方法的名称中。将此与大多数 jQuery 方法(如 afterinsertAfter)进行对比。

如果有人可以在不阅读文档或源代码的情况下直观地弄清楚 afterinsertAfter 做了什么,那么这个人就是天才。不幸的是,我不是一个 - 到目前为止,我仍然需要查看文档来弄清楚使用这两种方法时到底该放在哪里。

【讨论】:

  • +1 不错。我从来不明白只返回第一个结果的用处。
  • +1 或 afterinsertAfter 做什么。 appendappendTo 也很重要。
  • afterinsertAfter(以及它们的 before 对应物),另一个很好的例子。那些让我发疯!
  • 这是一个荒谬的论点。保持代码大小并不意味着我将我的变量命名为abcd 等。这是编译器的工作,或者minification,如果你说的是解释语言,特别是 JavaScript。
  • 库开发者也是程序员。编写高质量的代码对于库的用户和库的开发人员一样重要。事实上,选择好的描述性变量名非常重要,以至于一本最流行的软件构造书籍 (Code Complete) 有一个完整的章节专门介绍如何为变量选择好的名称。
【解决方案3】:

patrick dw 在他(出色的)答案中达到了大部分要点。只是用其他一些例子来添加到他的收藏中。

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

方法名称 正如帕特里克已经指出的那样; closest() 是一个垃圾方法名称。 prev()next() 在大多数人看来好像他们在做 prevAll()nextAll() 实际提供的工作。

delay() 让很多人感到困惑:在下面的例子中,你期望发生什么? (what actually happens?)

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

方法参数 很多树的遍历函数和他们接受的不一致;它们都接受选择器、jQuery 对象和元素的混合,但没有一个是一致的;考虑到他们都做类似的工作,这很糟糕。查看closest()find()siblings()parents()parent() 并比较差异!

在内部,jQuery 的“核心”最初包含许多相互交织的方法,开发团队在过去的版本中一直在努力拆分(并且做得非常好)。 css、属性、操作和遍历等内部模块过去都捆绑在同一个大包中。

【讨论】:

  • &lt;p&gt; 在该示例中永远不会被隐藏,您能解释一下原因吗?并为开发人员在可能被认为是一个糟糕的开始的情况下做得很好。
【解决方案4】:

包含在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(); 通过 post 发送 ajax 请求。

知道此列表中涵盖所有内容的内容吗?不是速记的一个功能,$.ajax,它功能齐全,涵盖了所有内容,您甚至可以将其配置为存储默认值并从本质上创建所有这些速记。如果您希望调用 ajax(这就是所有这些都做的),您可以创建自己的方法。

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

有人用速记写他们所有的代码:

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

好的,哦等等,我们想将其更改为从帖子中获取的 XML 提要,我们还需要在帖子之前和之后做一些事情。哦,让我们切换到非速记方法

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

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

这点,尤其是对于像 $.load() 这样的东西,越界说明为什么 PHP 有如此讨厌的 API,他们正在尝试做他们不应该做的事情。

要将其扩展到 AJAX 调用之外,请查看动画部分。我们调用了 slideUp、slideDown、fadeIn、fadeOut、fadeToggle、show 和 hide。为什么?我的左滑、右滑、滑入、滑出、传送以及我们能想到的所有其他东西在哪里?如果我们想要这些效果,为什么不坚持使用 $.animate() 并让某人编写插件。事实上,确实有人写了一个插件,jQueryUI 扩展了动画。这太疯狂了,导致人们不知道某些效果会在他们的 div 上创建 CSS 规则,最终会搞砸他们以后想做的事情。

保持纯粹,保持简单。

【讨论】:

  • 谁使用TRACECONNECT。来吧 ;)
  • 老实说,大多数浏览器除了 get 和 post 之外不允许任何东西,我列出这个列表真的是为了清楚地表明这种理念在扩展时是如何失败的。
  • @user257493 +1 for jQueryUI extension animate 我想知道为什么没有 jQueryUI jQuery animate 会中断。
  • 我想假设 jQuery 是“速记”常用方法。与$.deleteJSON(或许多其他列出的不存在的函数——甚至是XML 函数(这些天))相比,有人使用$.getJSON 的可能性要大得多。同样,slideDownslideLeft 更可能被使用
  • 然而,它遵循了他们“事半功倍”的理念。从字面上看,他们到处都有捷径。例如,.click.bind('click') 的快捷方式。
猜你喜欢
  • 2021-09-27
  • 2017-02-20
  • 1970-01-01
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
  • 2019-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多