zoukankan      html  css  js  c++  java
  • ExtJS与jQuery的一点细节上的对比

          首先说明这不是一篇完整解读ExtJS和jQuery所有方面差异的文章,只是针对我个人刚看了两天的jQuery产生的一些疑问的整理。之前用过一段时间ExtJS,了解ExtJS的一些机制。现在做移动开发,又选定了jquery mobile,要写控件,所以需要了解jquery。(不过换工作之后应该不会再用jQuery了,坑估计是短期内填不上了)

    1、jQuery是个什么东西?Ext是什么东西?(此处不是指两个框架,而是指我们在写程序的时候,经常用到的两个关键字--暂时称之为关键字)

        之前用的是ExtJS,Ext是个Object,通过字面量创建的,Ext.js文件里,3.3.1版: 

    Js代码  
    1. Ext = {  
    2.  version : '3.3.1',  
    3.  versionDetail : {  
    4.   major : 3,  
    5.   minor : 3,  
    6.   patch : 1  
    7.  }  
    8. };   

          4.0版本,此处global == window:

    Js代码  
    1. if (typeof Ext === 'undefined') {  
    2.      global.Ext = {};  
    3. }  

        既然Ext是个Object,那jQuery是不是也是个Object呢?NO,来分析下源码,jquery.js:

    Js代码  
    1. var jQuery = (function() {  
    2.   // Define a local copy of jQuery  
    3.   var jQuery = function( selector, context ) {  
    4.     // The jQuery object is actually just the init constructor 'enhanced'  
    5.     return new jQuery.fn.init( selector, context, rootjQuery );  
    6.    },    
    7.    ...//此处省略900行  
    8.   return jQuery;  
    9. })();  

        此处大概明白了,jQuery是个Function,并且由于此处调用jQuery的时候,有个return,所以var v = jQuery(xxx)和var v = new jQuery(xxx)调用后,v都是同一个函数的实例。在《JavaScript高级程序设计》第18章第一节有提到过这种技巧,叫做作用域安全的构造函数,不过书上提到的形式稍有差异:

    Js代码  
    1. function Person(name,age){  
    2.    if(this instanceof Person){  
    3.       this.name = name;  
    4.       this.age = age;  
    5.    }else{  
    6.       return new Person(name,age);  
    7.    }  
    8. }  

         这样var p = Person('a',21)和var p = new Person('a',21) ,p就都是Person实例了,如果去掉if判断和else后边的内容,第一种调用p是undefined。

        在jquery.js最后,把变量jQuery赋值给了$,后续可以通过$这种简写使用jQuery,算是一个简写的别名吧:

    Js代码  
    1. window.jQuery = window.$ = jQuery;   

          此处先挖个坑,构造函数中(如此处的Person)的this到底怎么理解?

    2、jQuery和Ext在这两个关键字都怎么使用的,有何异同?

        2.1、Ext是个对象,是一个命名空间,跟java里头的package类似,使用Ext下边的方法、Function/类的时候,就像使用一个对象的属性一样,如工具方法Ext.apply、Ext.applyIf可以直接调用,构造函数Ext.json.DataStore,前边加new创建实例。关于这么做的好处,了解java package的好处的都知道那么一些吧,我只还记得避免命名冲突。

        2.2、jQuery首先是个Function,既然是个Function,那个就可以new,可以像Function一样调用,以下将解析几种jQuery调用方法的源码:

        jQuery(xxx)的时候,转调到

    Js代码  
    1. new jQuery.fn.init(selector,context,rootjQuery)   

    具体调用时候就需要分析jQuery.prototype.init函数了。

             2.2.1、jQuery(function(){}),当传入是function的时候,init方法片段:

    Js代码  
    1. else if ( jQuery.isFunction( selector ) ) {  
    2.     return rootjQuery.ready( selector );  
    3. }  

             此处rootjQuery默认又等于jQuery(document);ready实际上就是在为document注册load事件,源码:

    Js代码  
    1. ready: function( fn ) {  
    2.       // Attach the listeners  
    3.       jQuery.bindReady();  
    4.       // Add the callback  
    5.       readyList.done( fn );  
    6.       return this;  
    7.    }  

             bindReady方法是通过attachEvent/addEventListener为document注册了load事件。

    Java代码  
    1. bindReady: function() {  
    2.      if ( readyList ) {  
    3.          return;  
    4.      }  
    5.      readyList = jQuery._Deferred();  
    6.      // Catch cases where $(document).ready() is called after the  
    7.      // browser event has already occurred.  
    8.      if ( document.readyState === "complete" ) {  
    9.          // Handle it asynchronously to allow scripts the opportunity to delay ready  
    10.          return setTimeout( jQuery.ready, 1 );  
    11.      }  
    12.      // Mozilla, Opera and webkit nightlies currently support this event  
    13.      if ( document.addEventListener ) {  
    14.          // Use the handy event callback  
    15.          document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );  
    16.          // A fallback to window.onload, that will always work  
    17.          window.addEventListener( "load", jQuery.ready, false );  
    18.      // If IE event model is used  
    19.      } else if ( document.attachEvent ) {  
    20.          // ensure firing before onload,  
    21.          // maybe late but safe also for iframes  
    22.          document.attachEvent( "onreadystatechange", DOMContentLoaded );  
    23.          // A fallback to window.onload, that will always work  
    24.          window.attachEvent( "onload", jQuery.ready );  
    25.          ……  
    26.      }  
    27.   }  

           2.2.2、jQuery(DOMElement)当传入参数是一dom element的时候,init方法片段:

    Js代码  
    1. if ( selector.nodeType ) {  
    2.      this.context = this[0] = selector;  
    3.      this.length = 1;  
    4.      return this;  
    5.  }  

        把dom元素放到了new出来的init对象上,此处this应该是一个对象,应该是个Object的,但是从Chrome调试看,此时this竟然显示为jQuery.fn.jQuery.init[0],Object.prototype.toString.call(this)结果是”[object Object]”,是个对象,为何显示这么奇怪呢?在FF里,this显示为[],按照道理说,对象应该不会这么显示的才对。

        此处把元素赋值为this[0]可以在后续访问元素的时候,直接用返回实例的[0]来访问,如果是多个元素,则可以用下标一个个的访问,后边看到selector的时候会看到。同时由于后边把init的原型指向了jQuery的原型,所以这里this的原型方法都是jQuery.prototype的方法:

    Js代码  
    1. jQuery.fn = jQuery.prototype = ……  
    2. jQuery.fn.init.prototype = jQuery.fn;  

         挖坑,关于原型方法,实例的关系。

             2.2.3、如果传入是body,jQuery(“body”),返回只有一个body元素

    Js代码  
    1. if ( selector === "body" && !context && document.body ) {  
    2.     this.context = document;  
    3.     this[0] = document.body;  
    4.     this.selector = selector;  
    5.     this.length = 1;  
    6.     return this;  
    7. }  

               2.2.4、jQuery(selector),如jquery.mobile.js中initializePage中$(“:jqmData(role=’page’)”)

    Js代码  
    1. // Handle HTML strings  
    2. if ( typeof selector === "string" ) {  
    3.    // Are we dealing with HTML string or an ID?  
    4.    if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {  
    5.       // Assume that strings that start and end with <> are HTML and skip the regex check  
    6.       match = [ null, selector, null ];  
    7.    } else {  
    8.       match = quickExpr.exec( selector );  
    9.    }  
    10.    // Verify a match, and that no context was specified for #id  
    11.    if ( match && (match[1] || !context) ) {  
    12.       ……//省略几十行,这一段是避免xss攻击什么的,没读懂,以后再来读  
    13.           return this;  
    14.       }  
    15.    // HANDLE: $(expr, $(...))  
    16.    } else if ( !context || context.jquery ) {  
    17.       return (context || rootjQuery).find( selector );  
    18.    // HANDLE: $(expr, context)  
    19.    // (which is just equivalent to: $(context).find(expr)  
    20.    } else {  
    21.       return this.constructor( context ).find( selector );  
    22.    }  
    23. }  

         如果传入的context为空,就从当前对象查找find(selector)否则就从rootjQuery查找,这里rootjQuery是个实力,所以此方法调用就是调用的原型上的find方法:

    Js代码  
    1. jQuery.fn.extend({  
    2.     find: function( selector ) {  
    3.        var self = this,  
    4.            i, l;  
    5.        ……//此处省略10+行  
    6.        var ret = this.pushStack( "", "find", selector ),  
    7.            length, n, r;  
    8.        for ( i = 0, l = this.length; i < l; i++ ) {  
    9.            length = ret.length;  
    10.            jQuery.find( selector, this[i], ret );  
    11.            if ( i > 0 ) {  
    12.               // Make sure that the results are unique  
    13.               for ( n = length; n < ret.length; n++ ) {  
    14.                   for ( r = 0; r < length; r++ ) {  
    15.                      if ( ret[r] === ret[n] ) {  
    16.                          ret.splice(n--, 1);  
    17.                          break;  
    18.                      }  
    19.                   }  
    20.               }  
    21.            }  
    22.        }  
    23.        return ret;  
    24. }  

         此处又调用到了jQuery.find方法,注意,jQuery是一个Function,这个find跟rootjQuery不同,jQuery.find是function的一个属性,非严格意义上可以简单的认为类似于java的静态方法。此find方法实则是Sizzle本身:

    jQuery.find = Sizzle; 

        具体实现还要看selector的内容,可能是getTagByName或者querySelectorAll,如getTagByName(‘name’)、querySelectorAll(“[data-role=’page’]”)。

             2.2.5、jQuery()如果传入为空,则返回不包含元素的jQuery对象:

    Js代码  
    1. if (!selector ) {  
    2.       return this;  
    3. }  

           2.2.6、jQuery(jQuery()),也就是传一个jQuery实例进去,会创建一个新对象,然后把老对象的内容拷贝到新对象里头。

        综上,jQuery()返回的是一个jQuery.prototype.init函数的实例,但是由于这个函数的原型指向了jQuery函数的原型,jQuery.prototype上的方法也可以直接在这个实例上调用。同时jQuery会被当成一个数组来使用,根据下标索引提取满足参数的dom元素。

    2.3、jQuery接着:-)也起到命名空间的作用。

    虽然jQuery是个function,但是可以在function上添加属性(这么叫准确么?)然后就可以直接jQuery.method()、jQuery.filed的调了。这里jQuery至少起到了一个命名空间的作用。 

           既然说到命名空间了,就不得不说jQuery的原型和function的方法,jQuery.method()类似静态方法,可以通过

    Js代码  
    1. jQuery.method=function(){}  
    2. jQuery.extend({method:function(){}})   

    两种方法来添加。原型方法则通过jQuery.fn.extend / jQuery.prototype.extend来添加。      

    3、jQuery和Ext都怎么实现继承的,有什么异同?各有什么优势?

           JavaScript是一门基于对象的语言,但不是面向对象,也就是说语言层面没有提供继承的语法,但是可以通过应用层面实现继承。由于把这种实现放到了应用层面,所以实现就变得五花八门了,可以通过拷贝、原型链等。了解两种继承的调用方式对理解下边说到的实现原理是很有帮助的。

           3.1、Ext(3.x)的继承跟《JavaScript高级程序设计》里讲到的寄生组合模式类似,这种实现方式复杂,不太容易理解。具体是在当前类和超类之间插入一个空对象,作为子类的原型对象,这个空对象的构造函数的原型指向超类的原型,然后把子类的方法,全部放入到这个空对象上。这样可以做到方法通过原型链实现继承,实例属性通过借用构造函数实现继承。这种方法也是目前最完美的实现方案。ExtJS继承的源码解析参考这里

           3.2、jQuery的继承的实现是基于拷贝的,这种实现比较简单,容易理解。但是要注意的是,jQuery这个function本身和jQuery的原型都有继承方法,其中jQuery.extend是把方法、属性拷贝到function上,后续可以直接通过jQuery.method调用;jQuery.fn.extend是把方法、属性拷贝到jQuery的原型上,后续可以通过jQuery实例(实际是jQuery.fn.init的实例,这个init函数的原型指向jQuery的原型)调用:

    Js代码  
    1. jQuery.extend = jQuery.fn.extend = function() {  
    2.     var options, name, src, copy, copyIsArray, clone,  
    3.        target = arguments[0] || {}, i = 1,     
    4. length = arguments.length, deep = false;  
    5.     // Handle a deep copy situation  
    6.     if ( typeof target === "boolean" ) {  
    7.        deep = target;  
    8.        target = arguments[1] || {};  
    9.        // skip the boolean and the target  
    10.        i = 2;  
    11.     }  
    12.     // Handle case when target is a string or something (possible in deep copy)  
    13.     if ( typeof target !== "object" && !jQuery.isFunction(target) ) {  
    14.        target = {};  
    15.     }  
    16.     // extend jQuery itself if only one argument is passed  
    17.     if ( length === i ) {  
    18.        target = this;//如果参数只有一个,target就指向this  
    19.        --i;  
    20.     }  
    21.     for ( ; i < length; i++ ) {  
    22.        // Only deal with non-null/undefined values  
    23.        if ( (options = arguments[ i ]) != null ) {  
    24.            // Extend the base object  
    25.            for ( name in options ) {//开始复制  
    26.               src = target[ name ];  
    27.               copy = options[ name ];  
    28.               // Prevent never-ending loop  
    29.               if ( target === copy ) {  
    30.                   continue;  
    31.               }  
    32.               // Recurse if we're merging plain objects or arrays  
    33.               if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {  
    34.                   if ( copyIsArray ) {  
    35.                      copyIsArray = false;  
    36.                      clone = src && jQuery.isArray(src) ? src : [];  
    37.                   } else {  
    38.                      clone = src && jQuery.isPlainObject(src) ? src : {};  
    39.                   }  
    40.                   // Never move original objects, clone them  
    41.                   target[ name ] = jQuery.extend( deep, clone, copy );  
    42.               // Don't bring in undefined values  
    43.               } else if ( copy !== undefined ) {  
    44.                   target[ name ] = copy;  
    45.               }  
    46.            }  
    47.        }  
    48.     }  
    49.     // Return the modified object  
    50.     return target;  
    51. };  

         需要特别注意的是这个this,当jQuery.extend的时候,this指的是jQuery.fn.init这个function,后续的方法、属性复制是复制给function的;当通过jQuery.fn.extend的时候,this指向的是原型对象,后续的方法、属性复制是复制给了原型对象。

  • 相关阅读:
    mac Navicat连接Oracle报错ORA-21561: OID generation failed
    svn: E230001: Server SSL certificate verification failed: certificate issued
    mac删除系统应用出现mac Read-Only filesystem
    spring boot项目03:阅读启动源码
    spring boot项目02:Web项目(基础)
    spring boot项目01:非Web项目(基础)
    idea 单独引入jar_Iidea 单独引入jar_Intellij IDEA 添加jar包的三种方式ntellij IDEA 添加jar包的三种方式
    java输出pdf的依赖包,非maven,包名:spire.pdf.jar 下载
    IDEA Error:java: 无效的源发行版: 11错误
    SpringBoot官网以下载模板方式创建
  • 原文地址:https://www.cnblogs.com/ranzige/p/3824470.html
Copyright © 2011-2022 走看看