jQuery框架结构简析

  一、 切入点:首先完成each方法和map方法的模拟;

    each方法: jQuery的each方法,返回一个jQuery对象,即一个伪数组,因此each方法实现了链式编程。另外,jQuery的each方法的回调函数返回false,结束循环,内部的this指向当前遍历的元素;

    map方法: jQuery的map方法中,根据回调函数的放回结果来返回,如果回调函数返回的是数组,那么map方法返回数组,如果回调函数中没有返回值,那么默认返回一个空数组。因此,map方法破坏了链式编程,内部的this不再指向遍历元素,而是window;  

  二、框架搭建:

    将整个框架的搭建放在一个沙箱中(闭包)

      (funtion(window){})(window);   // window 有两个作用: 一是减少作用域的搜索,而是提高压缩的效率

    需要一个函数,在此用MHQ表示;

    替换原型对象并还原构造器;

    影藏new关键字:  // MHQ并不通过new关键字,jQuery的做法是,在其原型对象上添加init构造函数,该构造函数的实例就是MHQ;

    现在的问题是MHQ.prototype.init()构造函数的实例怎么调用MHQ原型对象上的方法? jQuery的做法是: 让其原型对象上的init构造函数的原型对象指向其原型对象,也就是说:让MHQ.prototype.init.prototype = MHQ.prototype;

    那么现在如何要让闭包中的MHQ暴漏给外部访问呢? 答案是将其挂到全局window上,于是有了window.MHQ = window.M = MHQ; MHQ就是jQuery,那么M就是$,现在,window.MHQ就直接访问MHQ原型上的方法了。

    现在的问题是:如何给jQuery扩展方法呢?   jQuery的做法是直接添加静态属性和实例方法,实现混入继承。  MHQ.extend=MHQ.fn.extend=function(obj){for(var key in obj){this[k]=obj[k]}};将一个对象中的属性和方法拷贝一份供自己使用;

    另外jQuery中为了避免出现错误将所有的变量声明提前。

 1 (function(window){
 2     function MHQ(selector){
 3         return new MHQ.fn.init(selector);
 4     }
 5     MHQ.fn = MHQ.prototye = {
 6         constructor: MHQ,
 7         length:0,
 8         init: function(selector){
 9             // 对传入选择器的一系列的判断
10         }
11     };
12     MHQ.fn.init.prototype = MHQ.fn;
13     MHQ.extend = MHQ.fn.extend = function(obj){
14         var k;
15         for(k in obj){
16             this[k] = obj[k];
17         }
18     };
19     // 扩展实例方法,通过MHQ.fn.init(selector)的实例来访问
20     MHQ.fn.extend({...});
21     // 扩展静态方法,一般是工具类方法,如each,map
22     MHQ.extend({...});
23     window.MHQ = window.M = MHQ;
24 })(window); 

  三、首先根据切入点一的分析封装each和map方法

    这里需要明确jQuery的$符里面能够传入的类型有:jQuery对象,字符串(html格式字符串和选择器),DOM对象,函数等,因此需要判断传入的类型,因此也就有了其对应的判断方式。

  四、toArray方法和get方法的封装

    其中toArray方法没有参数,get方法不传参返回DOM元素的真数组,传入参数为正数,返回对应下标的DOM元素,为负数从this.length开始计算返回DOM元素;

  五、DOM操作的一些方法的封装

    在此需要注意的是链破坏,恢复链;

 

  1 /**
  2  * Created by mhq on 2016/10/26.
  3  */
  4 // window 的两个作用: 减少作用域的搜素,提高压缩效率
  5 (function (window) {
  6     /*在闭包内部作用域中定义变量,提高效率*/
  7     var arr = [];
  8     var push = arr.push;
  9     var slice = arr.slice;
 10
 11     // MHQ的原型对象中的init构造函数创建对象,影藏了new关键字,返回一个伪数组
 12     function MHQ(selector) {
 13         return new MHQ.fn.init(selector);
 14     }
 15     // 替换原型对象的方式实现继承
 16     MHQ.fn = MHQ.prototype = {
 17         // 还原构造器
 18         constructor: MHQ,
 19         // 添加length属性,返回时是伪数组
 20         length: 0,
 21         init: function (selector) {
 22             // 判断选择器类型
 23             if (!selector) return this;
 24             if (typeof selector === "string") {
 25                 // HTML格式的字符串
 26                 if (selector.charAt(0) === "<") {
 27                     push.apply(this, parseHTML(selector));
 28                     return this;
 29                 } else { // 选择器
 30                     push.apply(this, document.querySelectorAll(selector));
 31                     return this;
 32                 }
 33             }
 34             if (typeof selector === "function") {
 35                 // 传入类型是函数  将来处理事件
 36             }
 37             if (selector.nodeType) {  // 是DOM对象时
 38                 this[0] = selector;
 39                 this.length = 1;
 40                 return this;
 41             }
 42             if (selector.constructor.name === MHQ) { // 是MHQ类型的对象
 43                 return selector;
 44             }
 45             if (selector.length >= 0) { // 是数组或者伪数组
 46                 push.apply(this, selector);
 47             } else {
 48                 this[0] = selector;
 49                 this.length = 1;
 50             }
 51         }
 52     };
 53     // 使init构造函数的实例能够访问MHQ原型对象中的方法
 54     MHQ.fn.init.prototype = MHQ.fn;
 55     // 混入实现继承
 56     MHQ.extend = MHQ.fn.extend = function (obj) {
 57         var k;
 58         for (k in obj) {
 59             this[k] = obj[k];
 60         }
 61     };
 62
 63     MHQ.fn.extend({
 64         each: function (callback) {
 65             return MHQ.each(this, callback);
 66         },
 67         map: function (callback) {
 68             return MHQ.map(this, callback);
 69         }
 70     });
 71
 72     MHQ.extend({
 73         each: function (obj, callback) {
 74             var i,
 75                 len = obj.length,
 76                 isArray = len >= 0;
 77             if (isArray) {
 78                 for (i = 0; i < len; i++) {
 79                     if (callback.call(obj[i], i, obj[i]) === false) break;
 80                 }
 81             } else {
 82                 for (i in obj) {
 83                     if (callback.call(obj[i], i, obj[i]) === false) break;
 84                 }
 85             }
 86             return obj;
 87         },
 88         map: function (obj, callback) {
 89             var i,
 90                 len = obj.length,
 91                 isArray = len >= 0,
 92                 result,
 93                 ret = [];
 94             if (isArray) {
 95                 for (i = 0; i < len; i++) {
 96                     result = callback(obj[i], i);
 97                     if (result != null) {
 98                         ret.push(result);
 99                     }
100                 }
101             } else {
102                 for (i in obj) {
103                     result = callback(obj[i], i);
104                     if (result != null) {
105                         ret.push(result);
106                     }
107                 }
108             }
109             return ret;
110         },
111         next: function ( dom ) {
112             var node = dom;
113             while( node = node.nextSibling ) {
114                 if ( node.nodeType === 1 ) {
115                     return node;
116                 }
117             }
118             return null;
119         }
120     });
121
122     // 处理HTML字符串的方法
123     function parseHTML(htmlStr) {
124         var div = document.createElement("div"),
125             i = 0,
126             nodeArr = [];
127         div.innerHTML = htmlStr;
128         for (; i < div.childNodes.length; i++) {
129             nodeArr.push(div.childNodes[i]);
130         }
131         return nodeArr;
132     }
133
134     // 实现toArray方法、get方法(获取DOM元素)
135     MHQ.fn.extend({
136         toArray: function () {
137             return slice.call(this);
138         },
139         get: function (index) {
140             if (index === undefined) {
141                 return this.toArray();
142             } else {
143                 return this[index > 0 ? index : this.length + index];
144             }
145         }
146     });
147
148     // DOM元素操作模块
149     MHQ.fn.extend({
150         appendTo: function (selector) {
151             var i,
152                 j,
153                 tmpObj,
154                 ret = [],
155                 destinationObj = MHQ(selector);
156
157             for (i = 0; i < this.length; i++) {
158                 for (j = 0; j < destinationObj.length; j++) {
159                     tmpObj = j === destinationObj.length - 1 ? this[i] : this[i].cloneNode(true);
160                     ret.push(tmpObj);
161                     destinationObj[j].appendChild(tmpObj);
162                 }
163             }
164             return this.pushStack(ret);
165         },
166         prependTo: function (selector) {
167             // 将 this[i] 加入到 selector[j] 中, 链会破坏
168             // MHQ( selector ).prepend( this );
169             var tmpObj, ret = [],
170                 i, j,
171                 destinationObj = MHQ(selector);
172             for (i = 0; i < this.length; i++) {
173                 for (j = 0; j < destinationObj.length; j++) {
174                     tmpObj = j === destinationObj.length - 1 ? this[i] : this[i].cloneNode(true);
175                     ret.push(tmpObj);
176                     destinationObj[j].insertBefore(tmpObj, destinationObj[j].firstChild);
177                 }
178             }
179
180             return this.pushStack(ret);
181         },
182         prepend: function (selector) {
183             MHQ(selector).appendTo(this);
184             return this;
185         },
186         append: function (selector) {
187             // 将 selector[j] 加到 this[i] 中
188             // 不会造成链破坏
189             MHQ(selector).appendTo(this);
190             return this;
191         },
192         next: function () {
193             /*
194              var ret = [];
195              this.each(function () {
196              ret.push( this.nextElementSibling );
197              });
198              return this.pushStack( ret );
199              */
200             return this.pushStack(
201                 this.map(function ( v ) {
202                     return MHQ.next( v );
203                 }));
204         },
205         remove: function () {
206             this.each(function () {
207                 this.parentNode.removeChild(this);
208             });
209         }
210     });
211
212     // 恢复链
213     MHQ.fn.extend({
214         end: function () {
215             return this.prevObj || this;
216         },
217         pushStack: function (array) {
218             var newObj = MHQ(array);
219             newObj.prevObj = this;
220             return newObj;
221         }
222     });
223
224     window.MHQ = window.M = MHQ;
225
226 })(window);

  暂时先分析这些基本的功能实现过程。

  

  学习是一个辛苦但又兴奋的过程,只有通过不断的努力,才能勉强不让自己在快速发展的节奏中脱节。

时间: 2024-10-28 23:04:32

jQuery框架结构简析的相关文章

简析Spring MVC 数据解析

简析Spring MVC 数据解析 特别说明:本文使用spring 版本为 4.1.3 常用数据提交方式: 1. form 表单提交数据 1.1 解析form表单数据(无图片等数据) 前端代码事例: <form action="test/entity" method="post"> 用户ID:<input type="text" name="userid"/><br> 用户名:<inp

web应用构架LAMT及tomcat负载简析

Httpd    (mod_jk.so) workers.properties文件 uriworkermap.properties文件 <--AJP1.3--> Tomcat  --> jdk 大致流程:apache服务器通过mod_jk.so 模块处理jsp文件的动态请求.通过tomcat worker等待执行servlet/JSP的tomcat实例.使用 AJP1.3协议与tomcat通信.tomcat有借助jdk解析. 负载就是 多台tomcat.共同解析apache发送的jsp请

CentOS的网络配置简析

我们在进行对CentOS的网络配置时,一般会从IP地址(IPADDR).子网掩码(NETMASK).网关(Gateway).主机名(HOSTNAME).DNS服务器等方面入手.而在CentOS中,又有着不同的命令或配置文件可以完成这些配置操作,接下来,我们将从ifcfg系命令,iproute2系命令以及配置文件3个方面来简析网络配置的方法. 一.ifcfg系命令 ifcfg系命令包括ifconfig,route,netstat和hostname. 1.ifconfig命令 用来配置一个网络接口.

JDK源码简析--java.lang包中的基础类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.lang包所包

经验模态分解法简析 (转)

http://blog.sina.com.cn/s/blog_55954cfb0102e9y2.html 美国工程院士黄锷博士于1998年提出的一种信号分析方法:重点是黄博士的具有创新性的经验模态分解(Empirical Mode Decomposition)即EMD法,它是一种自适应的数据处理或挖掘方法,非常适合非线性,非平稳时间序列的处理,本质上是对数据序列或信号的平稳化处理. 1:关于时间序列平稳性的一般理解: 所谓时间序列的平稳性,一般指宽平稳,即时间序列的均值和方差为与时间无关的常数,

Java Annotation 及几个常用开源项目注解原理简析

PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示例 Override Annotation Java 1 2 3 @Override public void onCreate(Bundle savedInstanceState); Retrofit Annotation Java 1 2 3 @GET("/users/{username}&quo

Linux网络性能优化方法简析

Linux网络性能优化方法简析 2010-12-20 10:56 赵军 IBMDW 字号:T | T 性能问题永远是永恒的主题之一,而Linux在网络性能方面的优势则显而易见,这篇文章是对于Linux内核中提升网络性能的一些优化方法的简析,以让我们去后台看看魔术师表演用的盒子,同时也看看内核极客们是怎样灵活的,渐进的去解决这些实际的问题. AD:2014WOT全球软件技术峰会北京站 课程视频发布 对于网络的行为,可以简单划分为 3 条路径:1) 发送路径,2) 转发路径,3) 接收路径,而网络性

.NET设计模式简析

首先,是设计模式的分类,我们知道,常用的设计模式共23种.但总体来说,设计模式氛围三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单列模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模式,共十一种:策略模式.模版方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.转改模式.访问者模式.终结者模式.解释器模式. 另外还有并发型模式和线程池模式等. 介绍了分类,下面简单说下设计模式的六大原则

SpringMVC学习——概念、流程图、源码简析(一)

学习资料:开涛的<跟我学SpringMVC.pdf> 众所周知,springMVC是比较常用的web框架,通常整合spring使用.这里抛开spring,单纯的对springMVC做一下总结. 概念 HandlerMapping:处理器映射,对请求的URL进行映射为具体的处理器(如果有拦截器也包含拦截器,会将Handler和多个HandlerInterceptor封装为HandlerExecutionChain对象) HandlerAdapter:处理器适配器,适配不同类型的处理器,如Cont