JQUERY教程

当前位置: HTML5技术网 > JQUERY教程 > jQuery 中的编程范式(上)

jQuery 中的编程范式(上)

       浏览器前端编程的面貌自2005年以来已经发生了深刻的变化,这并不简单的意味着出现了大量功能丰富的基础库,使得我们可以更加方便的编写业务代码,更重要的是我们看待前端技术的观念发生了重大转变,明确意识到了如何以前端特有的方式释放程序员的生产力。本文将结合jQuery源码的实现原理,对javascript中涌现出的编程范式和常用技巧作一简单介绍。

       1. AJAX: 状态驻留,异步更新

       首先来看一点历史。

       A. 1995年Netscape公司的Brendan Eich开发了javacript语言,这是一种动态(dynamic)、弱类型(weakly typed)、基于原型(prototype-based)的脚本语言。

       B. 1999年微软IE5发布,其中包含了XMLHTTP ActiveX控件。

       C. 2001年微软IE6发布,部分支持DOM level 1和CSS 2标准。

       D. 2002年Douglas Crockford发明JSON格式。

       至此,可以说Web2.0所依赖的技术元素已经基本成形,但是并没有立刻在整个业界产生重大的影响。尽管一些“页面异步局部刷新”的技巧在程序员中间秘密的流传,甚至催生了bindows这样庞大臃肿的类库,但总的来说,前端被看作是贫瘠而又肮脏的沼泽地,只有后台技术才是王道。到底还缺少些什么呢?

       当我们站在今天的角度去回顾2005年之前的js代码,包括那些当时的牛人所写的代码,可以明显的感受到它们在程序控制力上的孱弱。并不是说2005年之前的js技术本身存在问题,只是它们在概念层面上是一盘散沙,缺乏统一的观念,或者说缺少自己独特的风格, 自己的灵魂。当时大多数的人,大多数的技术都试图在模拟传统的面向对象语言,利用传统的面向对象技术,去实现传统的GUI模型的仿制品。

       Ajax这一前端特有的概念迅速将众多分散的实践统一在同一口号之下,引发了Web编程范式的转换。所谓名不正则言不顺,这下无名群众可找到组织了。在未有Ajax之前,人们早已认识到了B/S架构的本质特征在于浏览器和服务器的状态空间是分离的,但是一般的解决方案都是隐藏这一区分,将前台状态同步到后台,由后台统一进行逻辑处理,例如ASP.NET。因为缺乏成熟的设计模式支持前台状态驻留,在换页的时候,已经装载的js对象将被迫被丢弃,这样谁还能指望它去完成什么复杂的工作吗?

       Ajax明确提出界面是局部刷新的,前台驻留了状态,这就促成了一种需要:需要js对象在前台存在更长的时间。这也就意味着需要将这些对象和功能有效的管理起来,意味着更复杂的代码组织技术,意味着对模块化,对公共代码基的渴求。

       jQuery现有的代码中真正与Ajax相关(使用XMLHTTP控件异步访问后台返回数据)的部分其实很少,但是如果没有Ajax, jQuery作为公共代码基也就缺乏存在的理由。

       2. 模块化:管理名字空间

       当大量的代码产生出来以后,我们所需要的最基础的概念就是模块化,也就是对工作进行分解和复用。工作得以分解的关键在于各人独立工作的成果可以集成在一起。这意味着各个模块必须基于一致的底层概念,可以实现交互,也就是说应该基于一套公共代码基,屏蔽底层浏览器的不一致性,并实现统一的抽象层,例如统一的事件管理机制等。比统一代码基更重要的是,各个模块之间必须没有名字冲突。否则,即使两个模块之间没有任何交互,也无法共同工作。

       jQuery目前鼓吹的主要卖点之一就是对名字空间的良好控制。这甚至比提供更多更完善的功能点都重要的多。良好的模块化允许我们复用任何来源的代码,所有人的工作得以积累叠加。而功能实现仅仅是一时的工作量的问题。jQuery使用module pattern的一个变种来减少对全局名字空间的影响,仅仅在window对象上增加了一个jQuery对象(也就是$函数)。

       所谓的module pattern代码如下,它的关键是利用匿名函数限制临时变量的作用域。
  1. var feature =(function() {
复制代码
       js本身缺乏包结构,不过经过多年的尝试之后业内已经逐渐统一了对包加载的认识,形成了RequireJs库这样得到一定共识的解决方案。jQuery可以与RequireJS库良好的集成在一起, 实现更完善的模块依赖管理。http://requirejs.org/docs/jquery.html

  1. require(["jquery", "jquery.my"], function() {
  2.     //当jquery.js和jquery.my.js都成功装载之后执行
  3.     $(function(){
  4.       $(‘#my’).myFunc();
  5.     });
  6.   });
复制代码

       通过以下函数调用来定义模块my/shirt, 它依赖于my/cart和my/inventory模块,

  1. require.def(“my/shirt”,
复制代码
       3. 神奇的$:对象提升

       当你第一眼看到$函数的时候,你想到了什么?传统的编程理论总是告诉我们函数命名应该准确,应该清晰无误的表达作者的意图,甚至声称长名字要优于短名字,因为减少了出现歧义的可能性。但是,$是什么?乱码?它所传递的信息实在是太隐晦,太暧昧了。$是由prototype.js库发明的,它真的是一个神奇的函数,因为它可以将一个原始的DOM节点提升(enhance)为一个具有复杂行为的对象。在prototype.js最初的实现中,$函数的定义为

  1. var $ = function (id) {
  2.   return ”string” == typeof id ? document.getElementById(id) : id;
  3. };
复制代码

       这基本对应于如下公式

  1. e = $(id)
复制代码

       这绝不仅仅是提供了一个聪明的函数名称缩写,更重要的是在概念层面上建立了文本id与DOM element之间的一一对应。在未有$之前,id与对应的element之间的距离十分遥远,一般要将element缓存到变量中,例如

  1. var ea = docuement.getElementById(‘a’);
  2. var eb = docuement.getElementById(‘b’);
  3. ea.style….
复制代码

       但是使用$之后,却随处可见如下的写法

  1. $(‘header_’+id).style…
  2. $(‘body_’+id)….
复制代码

       id与element之间的距离似乎被消除了,可以非常紧密的交织在一起。

       prototype.js后来扩展了$的含义,

  1. function $() {
  2.   var elements = new Array();

  3.   for (var i = 0; i < arguments.length; i++) {
  4.       var element = arguments[i];
  5.       if (typeof element == ’string’)
  6.         element = document.getElementById(element);

  7.       if (arguments.length == 1)
  8.         return element;

  9.       elements.push(element);
  10.   }

  11.   return elements;
  12. }
复制代码

       这对应于公式

  1. [e,e] = $(id,id)
复制代码

       很遗憾,这一步prototype.js走偏了,这一做法很少有实用的价值。

       真正将$发扬光大的是jQuery, 它的$对应于公式

  1. [o] = $(selector)
复制代码

       这里有三个增强

       A. selector不再是单一的节点定位符,而是复杂的集合选择符

       B. 返回的元素不是原始的DOM节点,而是经过jQuery进一步增强的具有丰富行为的对象,可以启动复杂的函数调用链。

       C. $返回的包装对象被造型为数组形式,将集合操作自然的整合到调用链中。

       当然,以上仅仅是对神奇的$的一个过分简化的描述,它的实际功能要复杂得多. 特别是有一个非常常用的直接构造功能

  1. $(“<table><tbody><tr><td>…</td></tr></tbody></table>”)….
复制代码

       jQuery将根据传入的html文本直接构造出一系列的DOM节点,并将其包装为jQuery对象. 这在某种程度上可以看作是对selector的扩展: html内容描述本身就是一种唯一指定。

       $(function{})这一功能就实在是让人有些无语了, 它表示当document.ready的时候调用此回调函数。真的,$是一个神奇的函数, 有任何问题,请$一下。

       总结起来, $是从普通的DOM和文本描述世界到具有丰富对象行为的jQuery世界的跃迁通道。跨过了这道门,就来到了理想国。

       4. 无定形的参数:专注表达而不是约束

       弱类型语言既然头上顶着个”弱”字, 总难免让人有些先天不足的感觉. 在程序中缺乏类型约束, 是否真的是一种重大的缺憾? 在传统的强类型语言中, 函数参数的类型,个数等都是由编译器负责检查的约束条件, 但这些约束仍然是远远不够的。一般应用程序中为了加强约束, 总会增加大量防御性代码, 例如在C++中我们常用ASSERT, 而在java中也经常需要判断参数值的范围:

  1. if (index < 0 || index >= size)
  2.     throw new IndexOutOfBoundsException(
  3.         ”Index: ”+index+”, Size: ”+size);
复制代码

       很显然, 这些代码将导致程序中存在大量无功能的执行路径, 即我们做了大量判断, 代码执行到某个点, 系统抛出异常, 大喊此路不通. 如果我们换一个思路, 既然已经做了某种判断,能否利用这些判断的结果来做些什么呢? javascript是一种弱类型的语言,它是无法自动约束参数类型的, 那如果顺势而行,进一步弱化参数的形态, 将”弱”推进到一种极致, 在弱无可弱的时候, weak会不会成为标志性的特点?

       看一下jQuery中的事件绑定函数bind,

       A. 一次绑定一个事件 $(“#my”).bind(“mouseover”, function(){});

       B. 一次绑定多个事件 $(“#my”).bind(“mouseover mouseout”,function(){})

       C. 换一个形式, 同样绑定多个事件 $(“#my”).bind({mouseover:function(){}, mouseout:function(){});

       D. 想给事件监听器传点参数 $(‘#my’).bind(‘click’, {foo: “xxxx”}, function(event) { event.data.foo..})

       E. 想给事件监听器分个组 $(“#my”).bind(“click.myGroup″, function(){});

       F. 这个函数为什么还没有疯掉???


       就算是类型不确定, 在固定位置上的参数的意义总要是确定的吧? 退一万步来说, 就算是参数位置不重要了,函数本身的意义应该是确定的吧? 但这是什么

  1. //取值
  2. value = o.val(),
  3. //设置值
  4. o.val(3)
复制代码
       一个函数怎么可以这样过分, 怎么能根据传入参数的类型和个数不同而行为不同呢? 看不顺眼是不是? 可这就是俺们的价值观. 既然不能防止, 那就故意允许. 虽然形式多变, 却无一句废话. 缺少约束, 不妨碍表达(我不是出来吓人的).

       未完待续。

【jQuery 中的编程范式(上)】相关文章

1. jQuery 中的编程范式(上)

2. jQuery 中的编程范式(中)

3. jQuery中的编程范式(下)

4. phonegap教程第7讲 Jquery Mobile插件(上)

5. 推荐20款基于 jQuery & CSS 的文本效果插件 (上)

6. CSS3 Animation(上)

7. 2012年11月“我最喜爱的编程语言”排行榜出炉

8. 浅谈JavaScript编程语言的编码规范

9. 什么是最好的编程语言?

10. 你应该学习的最好的编程语言

本文来源:https://www.51html5.com/a1112.html

点击展开全部

﹝jQuery 中的编程范式(上)﹞相关内容

「jQuery 中的编程范式(上)」相关专题

其它栏目

也许您还喜欢