读一个开源框架,大家最想学到的就是设计的思想和实现的技巧。最近读jQuery源码,记下我对大师作品的理解和心得,跟大家分享,权当抛砖引玉。

先附上jQuery的代码结构。

  1. (function(){
  2. //jQuery变量定义
  3. var jQuery  = function(){...};
  4. //jQuery原型定义(包含核心方法)
  5. jQuery.fn = jQuery.prototype = {...};
  6. //看上去很奇怪吧? 非常巧妙的设计,后面详细介绍
  7. jQuery.fn.init.prototype = jQuery.fn;
  8. //提供jQuery静态方法与对象方法的扩展函数
  9. jQuery.extend = jQuery.fn.extend = function(){...};
  10. //后面依次有多个对jQuery静态方法的扩展
  11. jQuery.extend({...});
  12. //后面依次有多个对jQuery对象方法的扩展
  13. jQuery.fn.extend({...});
  14. jQuery.support = (function() {...})();
  15. //提供统一时间管理,jQuery内部使用,并不对外开放
  16. jQuery.event = {...};
  17. //Event类似于Java的POJO类.传递事件的对象
  18. jQuery.Event = function( src, props ) {...};
  19. //Sizzle选择器,一个框架,可独立使用。
  20. (function(){
  21. ...
  22. jQuery.find = Sizzle;
  23. ...
  24. })();
  25. ...
  26. //将定义的jQuery定义为全局变量
  27. window.jQuery = window.$ = jQuery;
  28. ...
  29. })();

在结构上非常的清晰,定义一个jQuery对象,对jQuery对象进行扩展,赋给window,变成全局变量。就以下几点做介绍:

1). 自执行的匿名函数。

2). $("...")形式调用返回 jQuery.fn.init对象。

3). 框架里最常见的 extend 函数。

一. 自执行匿名函数。

对javascript有一定基础的都应该知道自执行匿名函数的好处。js是函数作用域。在函数里定义的变量都是局部变量,这样就很好的避免了过多的全局变量(jQuery仅仅2个全局变量jQuery和$)。由于闭包属性,虽然函数自执行结束了,但自执行函数里面定义的局部函数和变量还是能够被定义成全局变量的jQuery和$所引用到,类似于Java的私有变量。好处可见一斑。

二. $("...")形式调用返回 jQuery.fn.init对象。

这是我刚看源码的时候最不理解的地方。

  1. var jQuery = function( selector, context ) {
  2. // The jQuery object is actually just the init constructor 'enhanced'
  3. return new jQuery.fn.init( selector, context, rootjQuery );
  4. }
  5. jQuery.fn.init.prototype = jQuery.fn;
看懂这段我们先看看jQuery的使用。jQuery采用链式调用(如:$("#id").data("xxx")),这样就知道$("#id")返回的是一个jQuery对象。但是调用的方式是函数调用。这个问题就成为了:以函数的方式调用返回jQuery对象,并且构造函数是init。现在就围绕解决这个问题展开:
首先想到的是在函数式调用的时候返回一个jQuery对象。
  1. var jQuery = function( selector, context ) {
  2. return new jQuery( selector, context);
  3. }

兄弟,你确定这样? 明眼人一看就知道严重的问题所在,死递归!

既然不能调用本身,那我们想到另一种办法:再定义一个函数A,A的原型与jQuery的原型一样,那A的对象与jQuery生成的对象就是一模一样了(javascript是原型继承),而且将A的constructor定义为jQuery,上面的问题不是迎刃而解么?
 
  1. var jQuery = function( selector, context ) {
  2. return new A( selector, context);
  3. }
  4. var A = function(){
  5. if(this.init) {
  6. this.init();
  7. }
  8. };
  9. A.prototype = jQuery.prototype;

这样就解决了上面的问题,因为jQuery和A拥有同一个原型,所以生成的对象都拥有相同的方法。但是还是感觉A定义的有些多余,是不是?

既然定义A就为了返回A的对象,那init函数也能生成对象(以为js中没有类,定义的函数可以当函数执行,也能new成对象)。既然用init的话,那样init函数会自动执行,也不用再调用,岂不是更方便!所以就看到了我们之前看到的代码。
这里可能还有个fn解释下,其实这个fn没有什么特殊意思,只是jQuery.prototype的引用,jQuery支持自己扩展属性,这个对外提供了一个接口,jQuery.fn.extend()来对对象增加方法,比使用jQuery.prototype.extend()更好。封装想,字面就能看懂是对函数扩展,而不是看上去直接修改prototype.友好的用户接口。
相对于文字,图形化更加直观,对上面的引用来引用去画了个图,更好的理解:

其实在使用返回 new jQuery.fn.init( selector, context, rootjQuery ) 对象方式,我还有另一种实现
  1. var jQuery = function( selector, context ) {
  2. //如果以$("#id") 方式调用this就不是jQuery.这样返回jQuery对象
  3. if(!(this instanceof jQuery)) {
  4. return new jQuery(selector, context);
  5. }
  6. if(this.init) {
  7. this.init();
  8. }
  9. }
  10. //这行就可以注释了
  11. //jQuery.fn.init.prototype = jQuery.fn;
这种经过测试时可以的,不知道还有没有其他的隐蔽问题,暂时没发现,也算是一种实现吧。供大家参考。
三. 框架里最看到的 extend 函数
在后面的段落中有大段大段的 jQuery.extend({...}) 和 jQuery.fn.extend({...}) 代码。这里先解释下这个的作用和不同。
extend 在java中是继承,在我之前写的一篇 <简单实现Javascrip继承> 文章不同,也都是用了extend关键字。那些我们都说叫继承,而这里我更加喜欢叫扩展。为什么呢? 继承是产生了新的类,而这里没有,这里的2个函数第一个是扩展jQuery的静态方法,而第二个是用户自己扩展对象的方法。静态方法?对象方法?这里我来做个解释,在jQuery中有2中调用形式:
1)$.Ajax(...);
2)$("#id").data("xxx");
第一种调用我称为静态调用,就类似于Java的静态方法一样,不用生成对象,而是类级函数。这里的$就相当于命名空间一样。我们知道在以往js的编程中,如果有命名空间我们都这样:
var ns = {};
ns.Ajax = function(){...};
那为什么这里不是对象,而是函数做一个命名空间呢? 其实在js中一切都是对象!包括函数也是对象(说Java一切都是对象,我觉得其实这句话形容js更加贴切)。
第二种调用我成为对象调用,因为.data()方法是定义在原型中的,只有new个对象才能调用的,所以成为对象方法。
我们看代码jQuery.extend = jQuery.fn.extend = function(){...}; 这个是连等,也就是2个指向同一个函数,怎么会实现不同的功能呢?这就是this 的功能了。jQuery.extend 调用的时候,this是指向jQuery对象的(jQuery是函数,也是对象!),所以这里扩展在jQuery上。 而jQuery.fn.extend 调用的时候,this指向fn对象,而上图中科院看到,jQuery.fn 和jQuery.prototype指向同一对象,扩展fn就是扩展jQuery.prototype原型对象。这里增加的是原型方法,也就是对象方法了。所以jQuery的api中提供了以上2中扩展函数。
本章结束,有不对和不准确的地方望大家指正。有疑问可以留言。
下篇介绍jQuery的data实现。欢迎关注。

读jQuery源码之整体框架分析的更多相关文章

  1. 读jQuery源码 - Deferred

    Deferred首次出现在jQuery 1.5中,在jQuery 1.8之后被改写,它的出现抹平了javascript中的大量回调产生的金字塔,提供了异步编程的能力,它主要服役于jQuery.ajax ...

  2. jQuery源码解读 --- 整体架构

    最近学习比较忙,感觉想要提高还是要读源码,所以准备考试这个考试结束就开始读jquery源码啦,加油~

  3. 【jQuery源码】整体架构

    jQuery源码可以精简为以下内容: 方框上面的代码根据Jq注释我们可以知道是对AMD规范的支持. jQuery整体上被包裹在一个匿名函数中,这个匿名函数再作为另一个匿名函数的参数被传入,形参fact ...

  4. 读jQuery源码有感

    读之前的预备工作: 1.基础的js知识,以及html和css知识,和正则表达式知识.可以参考妙味课堂的基础js,html和css大纲. 2.JavaScript核心指南的知识http://www.cn ...

  5. 读jQuery源码 - Callbacks

    代码的本质突出顺序.有序这一概念,尤其在javascript——毕竟javascript是单线程引擎. javascript拥有函数式编程的特性,而又因为javascript单线程引擎,我们的函数总是 ...

  6. 读jQuery源码有感2

    那么就来读读jQuery源码的Callbacks部分. 一上来看原版源码 jQuery.Callbacks = function( options ) { // Convert options fro ...

  7. 读jQuery源码释疑笔记2

    本释疑笔记是针对自己在看源码的过程中遇到的一些问题的解答,对大众可能不具有参考性,不过可以看看有没有你也不懂得地方,相互学习,相互进步. 1.函数init <div id="one&q ...

  8. 读jQuery源码释疑笔记

    本释疑笔记是针对自己在看源码的过程中遇到的一些问题的解答,对大众可能不具有参考性,不过可以看看有没有你也不懂得地方,相互学习,相互进步.  1.each的用法 之前对each的用法一直迷迷糊糊,这次终 ...

  9. 一步步去阅读koa源码,整体架构分析

    阅读好的框架的源码有很多好处,从大神的视角去理解整个框架的设计思想.大到架构设计,小到可取的命名风格,还有设计模式.实现某类功能使用到的数据结构和算法等等. 使用koa 其实某个框架阅读源码的时候,首 ...

随机推荐

  1. Scenes in Cocos2D

    https://www.makeschool.com/docs/?source=mgwu#!/cocos2d/1.0/scenes Scenes in Cocos2D In Cocos2D you h ...

  2. python 二分法查找思考理解小白向け

    首先说一下二分法查找的思路.这是面向小白的课程,大佬请让步谢谢 给定一个有序的序列(必须是排好序的)例如[1,2,3,4,5,6,7,8,9,10,20,30,400],然后我们查询一个元素出现的坐标 ...

  3. 使用MyQR生成二维码

    from MyQR import myqr # 主要用到以下几个参数 # words:文本,可以是一个链接,或者你想说的话 # picture:你用到的图片,作为背景,不然只是一个光秃秃的二维码 # ...

  4. sql server判断数据库、表、列、视图是否存在

    1 判断数据库是否存在 if exists (select * from sys.databases where name = '数据库名') drop database [数据库名] 2 判断表是否 ...

  5. hdu 1558(计算几何+并查集)

    Segment set Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  6. Spfa【P1813】拯救小tim_NOI导刊2011提高(02)

    Description 小tim在游乐场,有一天终于逃了出来!但是不小心又被游乐场的工作人员发现了„„所以你的任务是安全地把小tim护送回家.但是,A市复杂的交通状况给你出了一大难题. A市一共有n个 ...

  7. docker网络及Dockerfile

    1.制作镜像 使用阿里的yum源,网址:https://opsx.alibaba.com/mirror,或者mirrors.aliyun.com,点击帮助,就会有弹框出来. docker pull c ...

  8. hdu 1556 Color the ball 线段树

    题目链接:HDU - 1556 N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气 ...

  9. Bluetooth篇 开发实例之十 官网的Bluetooth Chat sample app.

    运行的时候,会报错: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.Action ...

  10. 合理配置SQL Server的最大内存

    http://blog.itpub.net/26435490/viewspace-1481846/