首页 > 学院 > 开发设计 > 正文

ExtJS与jQuery的一点细节上的对比

2019-11-17 01:36:37
字体:
来源:转载
供稿:网友

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(typeofExt==='undefined'){
  2. global.Ext={};
  3. }

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

Js代码
  1. varjQuery=(function(){
  2. //DefinealocalcopyofjQuery
  3. varjQuery=function(selector,context){
  4. //ThejQueryobjectisactuallyjusttheinitconstructor'enhanced'
  5. returnnewjQuery.fn.init(selector,context,rootjQuery);
  6. },
  7. ...//此处省略900行
  8. returnjQuery;
  9. })();

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

Js代码
  1. functionPerson(name,age){
  2. if(thisinstanceofPerson){
  3. this.name=name;
  4. this.age=age;
  5. }else{
  6. returnnewPerson(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. newjQuery.fn.init(selector,context,rootjQuery)

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

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

Js代码
  1. elseif(jQuery.isFunction(selector)){
  2. returnrootjQuery.ready(selector);
  3. }

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

Js代码
  1. ready:function(fn){
  2. //Attachthelisteners
  3. jQuery.bindReady();
  4. //Addthecallback
  5. readyList.done(fn);
  6. returnthis;
  7. }

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

Java代码
  1. bindReady:function(){
  2. if(readyList){
  3. return;
  4. }
  5. readyList=jQuery._Deferred();
  6. //Catchcaseswhere$(document).ready()iscalledafterthe
  7. //browsereventhasalreadyoccurred.
  8. if(document.readyState==="complete"){
  9. //Handleitasynchronouslytoallowscriptstheopportunitytodelayready
  10. returnsetTimeout(jQuery.ready,1);
  11. }
  12. //Mozilla,Operaandwebkitnightliescurrentlysupportthisevent
  13. if(document.addEventListener){
  14. //Usethehandyeventcallback
  15. document.addEventListener("DOMContentLoaded",DOMContentLoaded,false);
  16. //Afallbacktowindow.onload,thatwillalwayswork
  17. window.addEventListener("load",jQuery.ready,false);
  18. //IfIEeventmodelisused
  19. }elseif(document.attachEvent){
  20. //ensurefiringbeforeonload,
  21. //maybelatebutsafealsoforiframes
  22. document.attachEvent("onreadystatechange",DOMContentLoaded);
  23. //Afallbacktowindow.onload,thatwillalwayswork
  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. returnthis;
  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. returnthis;
  7. }

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

Js代码
  1. //HandleHTMLstrings
  2. if(typeofselector==="string"){
  3. //ArewedealingwithHTMLstringoranID?
  4. if(selector.charAt(0)==="<"&&selector.charAt(selector.length-1)===">"&&selector.length>=3){
  5. //Assumethatstringsthatstartandendwith<>areHTMLandskiptheregexcheck
  6. match=[null,selector,null];
  7. }else{
  8. match=quickExpr.exec(selector);
  9. }
  10. //Verifyamatch,andthatnocontextwasspecifiedfor#id
  11. if(match&&(match[1]||!context)){
  12. ……//省略几十行,这一段是避免xss攻击什么的,没读懂,以后再来读
  13. returnthis;
  14. }
  15. //HANDLE:$(expr,$(...))
  16. }elseif(!context||context.jquery){
  17. return(context||rootjQuery).find(selector);
  18. //HANDLE:$(expr,context)
  19. //(whichisjustequivalentto:$(context).find(expr)
  20. }else{
  21. returnthis.constructor(context).find(selector);
  22. }
  23. }

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

Js代码
  1. jQuery.fn.extend({
  2. find:function(selector){
  3. varself=this,
  4. i,l;
  5. ……//此处省略10+行
  6. varret=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. //Makesurethattheresultsareunique
  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. returnret;
  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. returnthis;
  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高级程序设计》里讲到的寄生组

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表