为什么 jQuery 的理念更胜一筹
这个博客上已经有很多帖子谈论了 jQuery 和 Prototype 之间代码大小的差异。这些帖子的基本前提(我同意)是,由于 jQuery 代码的结构方式,与 Prototype 相比,框架中所有常见的 Javascript 设计模式在代码长度和复杂度上都得到了简化。
很长一段时间以来,我都是一个自认的 Prototype 爱好者。当我开始做 Rails 工作时,我发现了这个框架,对于 Rails 开发者来说,几乎没有其他选择。Prototype 以其所有丑陋,都被烘焙到了 Rails 中,而且很难放弃 Rails 通过手工编码 Javascript 带来的生产力提升。再讲下去,这就是我开始开发 jQuery on Rails 的原因,它的目标是允许 Rails 开发者使用 jQuery 作为 Prototype 的直接替代品。
但回到这篇文章的主题,jQuery 的编程理念比仅仅是代码大小更根本地不同。事实上,这种理念上的差异非常类似于 Java 和 Ruby 之间的理念差异,所以 Rails 社区如此完整地接受了 Prototype 真是讽刺。
让我们来看一些代码比较。首先,在某个节点之后添加一些任意 HTML。
在 Prototype 中
new Insertion.After('myId', 'Arbitrary HTML');
在 jQuery 中
$('#myId').after('Arbitrary HTML');
现在,我们并没有在减少代码混乱方面做太多的事情(尽管 jQuery 的代码更简洁),但 Prototype 和 jQuery 每个解决问题的方式都存在根本差异。
Prototype 创建了一系列单一的类,每个类都封装了一些功能。然后,开发者传入一个 id 和一些其他参数,类就会完成它应该做的事情。非常类似于 Java 封装功能的方式(比如 Math 类,例如)。 注意:这并不意味着 Java 不能以这种方式做事。
jQuery 从根本上以不同的方式解决问题。它将 HTML 节点的集合视为要传递消息的对象(更像是传统的 Ruby 方式)。因此,jQuery 并没有为在 HTML 节点之后添加文本创建单独的类,而是将功能粘贴到 jQuery 对象上,该对象由 $ 函数返回。相比之下,Prototype 的 $ 函数返回一个普通的 DOM 节点。
Prototype 试图通过在框架的最新 RC 中添加的 $$ 方法来实现类似的功能,但存在根本差异。虽然 Prototype 的 $$ 返回一个 DOM 元素数组,但 jQuery 的 $ 是整个框架的根本基础。几乎所有 jQuery 函数都绑定到 jQuery 对象,该对象由 $ 方法返回。
jQuery 方式的好处非常明显
- 链式调用。因为 jQuery 对象上粘贴了功能,所以它们返回其他 jQuery 对象,开发者可以向这些对象传递更多消息。jQuery 网站上的简单例子是$(“p.surprise”).addClass(“ohmy”).show(“slow”);
- 使用 CSS 选择器和 XPath 操作符。因为 jQuery 向对象传递消息,所以它可以在(并且已经)在 $ 方法中实现额外的选择器功能。粘贴到 jQuery 对象上的方法只看到一个包含一系列 DOM 元素的类似数组的对象。它并不关心我们是如何获得这些元素的。因此,插件开发者可以在 $ 方法中添加额外的解析器,或者更轻松地将额外的函数粘贴到 jQuery 对象上。
- 这就引出了插件开发。jQuery 的方式非常有利于插件开发。添加利用 jQuery 对象的功能非常容易,而且 jQuery 插件通常比它们的对应插件短得多。 jQuery 插件
- 自动循环。jQuery 方法需要自动循环遍历数组中的所有 DOM 元素,并应用所需的方法。因此,$(expression).after(‘some HTML’) 会透明地将 HTML 添加到表达式返回的每个元素之后。例如,$(‘p’).after(‘some HTML’) 会将‘some HTML’ 添加到页面上的每个 <p> 之后。就我个人而言,我认为在大多数情况下,消除代码中的迭代是我使用 jQuery 最重要的实际好处之一。
- 建立在自身之上。随着 jQuery 的成熟,在现有架构之上构建插件变得更容易。因为所有 jQuery 函数都会自动循环,所以使用现有的 jQuery 函数意味着讨厌的迭代几乎消失了。
还有更多,但贯穿所有好处的主线来自于 John Resig 对 jQuery 对象/数组的细致入微的处理方式,它让该对象/数组接收传递的消息,而不是构建各种单一的、需要从头开始构建的功能块。
其他一些例子
Prototype 中的 AJAX 更新器
new Ajax.Updater('placeholder', url, { method: 'get', parameters: par });
jQuery 中的 AJAX 更新器
$('#placeholder').load(url + par);
注意:这个例子没有涉及到如果我们想将响应加载到每个 <p> 对象中会得到的明显的迭代好处。
在 Prototype 中为元素添加类
Element.addClassName('element', 'className');
在 jQuery 中为元素添加类
$('#element').addClass('className');
在 Prototype 中为一组元素添加类
$$('.element').each(function(node) { Element.addClassName(node, 'className'); }
在 jQuery 中为一组元素添加类
$('.element').addClass('className');
最后一个例子最清楚地说明了方法论上的差异。因为 jQuery 向 jQuery 对象传递消息,所以代码几乎没有改变。jQuery 不关心我们现在是在向一组对象添加类还是向一个对象添加类;底层代码是相同的(将类添加到对象中的元素集合中)。另一方面,Prototype 需要迭代器。
随着代码变得越来越复杂,jQuery 的扩展性很好,而嵌套循环在 Prototype 等框架中却成为常态。
[更新] 一位敏锐的读者(Mislav)指出,Prototype 确实做了一些 jQuery 所做的事情。Prototype 似乎将 Element 类绑定到 DOM 元素,允许像 $(‘myElement’).hide() 这样的操作,等等。然而,它只适用于 Element 模块,并且似乎只适用于单个 DOM 元素。绑定 Elements 模块很酷,但这更像是一种事后诸葛亮,而不是 jQuery 将其作为一项基本的设计决策的方式。
对于我的大多数项目来说,jQuery 很棒。在其他一些项目中,我使用的是 Prototype,但这都是关于使用最适合完成任务的工具。
对于那些抱怨的人来说,你可以*使用任何你想要的*。如果你不能,那就学习如何处理多个框架并提高你的编码技能,这是你的问题。此外,就像一些人发布的那样……因为你不同意背后的社区而不用一个框架?真的吗?我敢打赌,在实际工作中,选择一个东西不是因为它正确,而是因为它“社区”更好,这会很受欢迎。
PS。我讨厌 Javascript。该死的 AJAX 嬉皮士。
Pingback: JQuery vs. Prototype | Phine Solutions
Pingback: What Makes jQuery a Good Choice?
jQuery 和/或 Prototype 与一些服务器端框架(比如 JSF + Richfaces,这是我的目标)的兼容性如何?
我正在研究它们的兼容性,以及用客户端库替换基于 Ajax 的服务器端库的可能性。
Pingback: the time has come: converting Prototype into jQuery