JQUERY教程

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

jQuery中的编程范式(下)

       10. extend: 继承不是必须的

        js是基于原型的语言, 并没有内置的继承机制, 这一直让很多深受传统面向对象教育的同学们耿耿于怀。但继承一定是必须的吗? 它到底能够给我们带来什么? 最纯朴的回答是: 代码重用。那么, 我们首先来分析一下继承作为代码重用手段的潜力。

        曾经有个概念叫做”多重继承”, 它是继承概念的超级赛亚人版, 很遗憾后来被诊断为存在着先天缺陷, 以致于出现了一种对于继承概念的解读: 继承就是”is a”关系, 一个派生对象”is a”很多基类, 必然会出现精神分裂, 所以多重继承是不好的。

  1. class A{ public: void f(){ f in A } }
  2. class B{ public: void f(){ f in B } }
  3. class D: public A, B{}
复制代码

        如果D类从A,B两个基类继承, 而A和B类中都实现了同一个函数f, 那么D类中的f到底是A中的f还是B中的f, 抑或是A中的f+B中的f呢? 这一困境的出现实际上源于D的基类A和B是并列关系, 它们满足交换律和结合律, 毕竟,在概念层面上我们可能难以认可两个任意概念之间会出现从属关系。但如果我们放松一些概念层面的要求, 更多的从操作层面考虑一下代码重用问题, 可以简单的认为B在A的基础上进行操作, 那么就可以得到一个线性化的结果。也就是说, 放弃A和B之间的交换律只保留结合律, extends A, B 与 extends B,A 会是两个不同的结果, 不再存在诠释上的二义性。scala语言中的所谓trait(特性)机制实际上采用的就是这一策略。

        面向对象技术发明很久之后, 出现了所谓的面向方面编程(AOP), 它与OOP不同, 是代码结构空间中的定位与修改技术。AOP的眼中只有类与方法, 不知道什么叫做意义。AOP也提供了一种类似多重继承的代码重用手段, 那就是mixin。对象被看作是可以被打开,然后任意修改的Map, 一组成员变量与方法就被直接注射到对象体内, 直接改变了它的行为。

        prototype.js库引入了extend函数,

  1. Object.extend = function(destination, source) {
  2.   for (var property in source) {
  3.     destination[property] = source[property];
  4.   }
  5.   return destination;
  6. }
复制代码

        就是Map之间的一个覆盖运算, 但很管用, 在jQuery库中也得到了延用. 这个操作类似于mixin, 在jQuery中是代码重用的主要技术手段—没有继承也没什么大不了的。

        11. 名称映射: 一切都是数据

        代码好不好, 循环判断必须少。循环和判断语句是程序的基本组成部分, 但是优良的代码库中却往往找不到它们的踪影, 因为这些语句的交织会模糊系统的逻辑主线, 使我们的思想迷失在疲于奔命的代码追踪中。jQuery本身通过each, extend等函数已经极大减少了对循环语句的需求, 对于判断语句, 则主要是通过映射表来处理. 例如, jQuery的val()函数需要针对不同标签进行不同的处理, 因此定义一个以tagName为key的函数映射表。

  1. valHooks: { option: {get:function(){}}}
复制代码

        这样在程序中就不需要到处写

  1. if(elm.tagName == ’OPTION’){
  2.   return …;
  3. }else if(elm.tagName == ’TEXTAREA’){
  4.   return …;
  5. }
复制代码

        可以统一处理

  1. (valHooks[elm.tagName.toLowerCase()] || defaultHandler).get(elm);
复制代码

        映射表将函数作为普通数据来管理, 在动态语言中有着广泛的应用。特别是, 对象本身就是函数和变量的容器, 可以被看作是映射表。jQuery中大量使用的一个技巧就是利用名称映射来动态生成代码, 形成一种类似模板的机制。例如为了实现myWidth和myHeight两个非常类似的函数, 我们不需要。

  1. jQuery.fn.myWidth = function(){
  2.     return parseInt(this.style.width,10) + 10;
  3.   }

  4.   jQuery.fn.myHeight = function(){
  5.     return parseInt(this.style.height,10) + 10;
  6.   }
复制代码

        而可以选择动态生成

  1. jQuery.each(['Width','Height'],function(name){
  2.   jQuery.fn['my'+name] = function(){
  3.     return parseInt(this.style[name.toLowerCase()],10) + 10;
  4.   }
  5. });
复制代码

        12. 插件机制:其实我很简单   

        jQuery所谓的插件其实就是$.fn上增加的函数, 那这个fn是什么东西?

  1. (function(window,undefined){
  2.   // 内部又有一个包装
  3.   var jQuery = (function() {
  4.     var jQuery = function( selector, context ) {
  5.           return new jQuery.fn.init( selector, context, rootjQuery );
  6.       }
  7.      ….
  8.     // fn实际就是prototype的简写
  9.     jQuery.fn = jQuery.prototype = {
  10.         constructor: jQuery,
  11.         init: function( selector, context, rootjQuery ) {…  }
  12.     }

  13.     // 调用jQuery()就是相当于new init(), 而init的prototype就是jQuery的prototype
  14.     jQuery.fn.init.prototype = jQuery.fn;

  15.     // 这里返回的jQuery对象只具备最基本的功能, 下面就是一系列的extend
  16.     return jQuery;
  17.   })();
  18.   …
  19.    // 将jQuery暴露为全局对象
  20.   window.jQuery = window.$ = jQuery;
  21. })(window);
复制代码

        显然, $.fn其实就是jQuery.prototype的简写。

        无状态的插件仅仅就是一个函数, 非常简单。

  1. // 定义插件
  2. (function($){
  3.     $.fn.hoverClass = function(c) {
  4.         return this.hover(
  5.             function() { $(this).toggleClass(c); }
  6.         );
  7.     };
  8. })(jQuery);

  9. // 使用插件
  10. $(‘li’).hoverClass(‘hover’);
复制代码

        对于比较复杂的插件开发, jQuery UI提供了一个widget工厂机制,

  1. $.widget(“ui.dialog”, {
  2.   options: {
  3.        autoOpen: true,…
  4.     },
  5.     _create: function(){ … },
  6.     _init: function() {
  7.        if ( this.options.autoOpen ) {
  8.            this.open();
  9.        }
  10.     },
  11.     _setOption: function(key, value){ … }
  12.     destroy: function(){ … }
  13. });
复制代码

        调用 $(‘#dlg’).dialog(options)时, 实际执行的代码基本如下所示:

  1. this.each(function() {
  2.       var instance = $.data( this, ”dialog” );
  3.       if ( instance ) {
  4.           instance.option( options || {} )._init();
  5.       } else {
  6.           $.data( this, ”dialog”, new $.ui.dialog( options, this ) );
  7.       }
  8.   }
复制代码

        可以看出, 第一次调用$(‘#dlg’).dialog()函数时会创建窗口对象实例,并保存在data中, 此时会调用_create()和_init()函数, 而如果不是第一次调用, 则是在已经存在的对象实例上调用_init()方法. 多次调用$(‘#dlg’).dialog()并不会创建多个实例。

        13. browser sniffer vs. feature detection

        浏览器嗅探(browser sniffer)曾经是很流行的技术, 比如早期的jQuery中

  1. jQuery.browser = {
  2.       version:(userAgent.match(/.+(?:rv|it|ra|ie)[/: ]([d.]+)/) || [0,'0'])[1],
  3.       safari:/webkit/.test(userAgent),
  4.       opera:/opera/.test(userAgent),
  5.       msie:/msie/.test(userAgent) && !/opera/.test(userAgent),
  6.       mozilla:/mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent)
  7. };
复制代码

        在具体代码中可以针对不同的浏览器作出不同的处理

  1. if($.browser.msie) {
  2.     // do something
  3. } else if($.browser.opera) {
  4.     // …
  5. }
复制代码

        但是随着浏览器市场的竞争升级, 竞争对手之间的互相模仿和伪装导致userAgent一片混乱, 加上Chrome的诞生, Safari的崛起, IE也开始加速向标准靠拢, sniffer已经起不到积极的作用。特性检测(feature detection)作为更细粒度, 更具体的检测手段, 逐渐成为处理浏览器兼容性的主流方式。

  1. jQuery.support = {
  2.       // IE strips leading whitespace when .innerHTML is used
  3.       leadingWhitespace: ( div.firstChild.nodeType === 3 ),
  4.       …
  5.   }
复制代码

        只基于实际看见的,而不是曾经知道的, 这样更容易做到兼容未来.

        14. Prototype vs. jQuery

        prototype.js是一个立意高远的库, 它的目标是提供一种新的使用体验,参照Ruby从语言级别对javascript进行改造,并最终真的极大改变了js的面貌。$, extends, each, bind…这些耳熟能详的概念都是prototype.js引入到js领域的。它肆无忌惮的在window全局名字空间中增加各种概念, 大有谁先占坑谁有理, 舍我其谁的气势。而jQuery则扣扣索索, 抱着比较实用化的理念, 目标仅仅是write less, do more而已。

        不过等待激进的理想主义者的命运往往都是壮志未酬身先死。当prototype.js标志性的bind函数等被吸收到ECMAScript标准中时, 便注定了它的没落。到处修改原生对象的prototype, 这是prototype.js的独门秘技, 也是它的死穴。特别是当它试图模仿jQuery, 通过Element.extend(element)返回增强对象的时候, 算是彻底被jQuery给带到沟里去了。prototype.js与jQuery不同, 它总是直接修改原生对象的prototype, 而浏览器却是充满bug, 谎言, 历史包袱并夹杂着商业阴谋的领域, 在原生对象层面解决问题注定是一场悲剧。性能问题, 名字冲突, 兼容性问题等等都是一个帮助库的能力所无法解决的。Prototype.js的2.0版本据说要做大的变革, 不知是要与历史决裂, 放弃兼容性, 还是继续挣扎, 在夹缝中求生。

        完!

【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/a1115.html

点击展开全部

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

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

其它栏目

也许您还喜欢