jQuery源码可以精简为以下内容:

  方框上面的代码根据Jq注释我们可以知道是对AMD规范的支持。

  jQuery整体上被包裹在一个匿名函数中,这个匿名函数再作为另一个匿名函数的参数被传入,形参factory。

一、自调用函数

  整个部分被自调用函数包裹,通过定义一个匿名函数,创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏全局的命名空间。

  自调用函数中的第一个参数相当于window,通过传入window变量,使得window由全局变量变为局部变量,当在jQuery代码块中访问window时,不需要将作用域链回退到顶层作用域,这样可以更快的访问window;这还不是关键所在,更重要的是,将window作为参数传入,可以在压缩代码时进行优化。

  第二个参数为包裹jQuery的匿名函数,在匿名参数中被调用——factory()。

二、jQuery的无new构建

  jQuery框架的核心就是从HTML文档中匹配元素并对其执行操作、

  例如:

$().find().css()
$().hide().html('....').hide().

  从上面的写法上至少可以发现2个问题

  1. jQuery对象的构建方式

  2 .jQuery方法的调用方式

分析一:jQuery的无new构建

  JavaScript是函数式语言,函数可以实现类,类就是面向对象编程中最基本的概念

var aQuery = function(selector, context) {
//构造函数
}
aQuery.prototype = {
//原型
name:function(){},
age:function(){}
} var a = new aQuery(); a.name();

  这是常规的使用方法,显而易见jQuery不是这样玩的

  jQuery没有使用new运行符将jQuery显示的实例化,还是直接调用其函数

  按照jQuery的抒写方式

$().ready()
$().noConflict()

  要实现这样,那么jQuery就要看成一个类,那么$()应该是返回类的实例才对

  所以把代码改一下:

var aQuery = function(selector, context) {
return new aQuery();
}
aQuery.prototype = {
name:function(){},
age:function(){}
}

  通过new aQuery(),虽然返回的是一个实例,但是也能看出很明显的问题,死循环了!


那么如何返回一个正确的实例?

  在javascript中实例this只跟原型有关系

  那么可以把jQuery类当作一个工厂方法来创建实例,把这个方法放到jQuery.prototye原型中

var aQuery = function(selector, context) {
return aQuery.prototype.init();
}
aQuery.prototype = {
init:function(){
return this;
}
name:function(){},
age:function(){}
}

  当执行aQuery() 返回的实例:

  很明显aQuery()返回的是aQuery类的实例,那么在init中的this其实也是指向的aQuery类的实例

  问题来了init的this指向的是aQuery类,如果把init函数也当作一个构造器,那么内部的this要如何处理?

var aQuery = function(selector, context) {
return aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
},
name: function() {},
age: 20
} aQuery().age //18

  这样的情况下就出错了,因为this只是指向aQuery类的,所以需要设计出独立的作用域才行


jQuery框架分隔作用域的处理

jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},

  很明显通过实例init函数,每次都构建新的init实例对象,来分隔this,避免交互混淆

  那么既然都不是同一个对象那么肯定又出现一个新的问题

例如:

var aQuery = function(selector, context) {
return new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
},
name: function() {},
age: 20
} //Uncaught TypeError: Object [object Object] has no method 'name'
console.log(aQuery().name())

  抛出错误,无法找到这个方法,所以很明显new的init跟jquery类的this分离了


怎么访问jQuery类原型上的属性与方法?

做到既能隔离作用域还能使用jQuery原型对象的作用域呢,还能在返回实例中访问jQuery的原型对象?

实现的关键点

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

  通过原型传递解决问题,把jQuery的原型传递给jQuery.prototype.init.prototype

  换句话说jQuery的原型对象覆盖了init构造器的原型对象

  因为是引用传递所以不需要担心这个循环引用的性能问题

var aQuery = function(selector, context) {
return new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
return this;
},
name: function() {
return this.age
},
age: 20
} aQuery.prototype.init.prototype = aQuery.prototype; console.log(aQuery().name()) //20

三、链式调用

  DOM链式调用的处理:

  1.节约JS代码.

  2.所返回的都是同一个对象,可以提高代码的效率

  通过简单扩展原型方法并通过return this的形式来实现跨浏览器的链式调用。

  利用JS下的简单工厂模式,来将所有对于同一个DOM对象的操作指定同一个实例。

  这个原理就超简单了

aQuery().init().name()

分解
a = aQuery();
a.init()
a.name()

  把代码分解一下,很明显实现链式的基本条件就是实例this的存在,并且是同一个

aQuery.prototype = {
init: function() {
return this;
},
name: function() {
return this
}
}

  所以我们在需要链式的方法访问this就可以了,因为返回当前实例的this,从而又可以访问自己的原型了

aQuery.init().name()

  优点:节省代码量,提高代码的效率,代码看起来更优雅

四、插件接口

  jQuery支持自己扩展属性,这个对外提供了一个接口,jQuery.fn.extend()来对对象增加方法

从jQuery的源码中可以看到,jQuery.extend和jQuery.fn.extend其实是同指向同一方法的不同引用

jQuery.extend = jQuery.fn.extend = function() {
jQuery.extend 对jQuery本身的属性和方法进行了扩展,扩展工具方法下的插件

jQuery.fn.extend 对jQuery.fn的属性和方法进行了扩展,扩展jquery对象下的插件

  通过extend()函数可以方便快速的扩展功能,不会破坏jQuery的原型结构

  jQuery.extend = jQuery.fn.extend = function(){...}; 这个是连等,也就是2个指向同一个函数,怎么会实现不同的功能呢?这就是this 力量了!

  针对fn与jQuery其实是2个不同的对象,在之前有讲述:

  • jQuery.extend 调用的时候,this是指向jQuery对象的(jQuery是函数,也是对象!),所以这里扩展在jQuery上。
  • 而jQuery.fn.extend 调用的时候,this指向fn对象,jQuery.fn 和jQuery.prototype指向同一对象,扩展fn就是扩展jQuery.prototype原型对象。
  • 这里增加的是原型方法,也就是对象方法了。所以jQuery的api中提供了以上2中扩展函数。
 1 jQuery.extend = jQuery.fn.extend = function() {
2 var src, copyIsArray, copy, name, options, clone,
3 target = arguments[0] || {},
4 i = 1,
5 length = arguments.length,
6 deep = false;
7
8 // Handle a deep copy situation
9 //判断第一个参数是否为boolean类型,也就是是否深度嵌套对象
10 if ( typeof target === "boolean" ) {
11 deep = target;
12
13 // skip the boolean and the target
14 //跳过第一个boolean参数
15 target = arguments[ i ] || {};
16 i++;
17 }
18
19 // Handle case when target is a string or something (possible in deep copy)
20 // 处理奇怪的情况,比如 jQuery.extend( 'hello' , {nick: 'casper})
21 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
22 target = {};
23 }
24
25 // extend jQuery itself if only one argument is passed
26 if ( i === length ) {
27 target = this;
28 i--;
29 }
30
31 for ( ; i < length; i++ ) {
32 // Only deal with non-null/undefined values
33 if ( (options = arguments[ i ]) != null ) {//opitions为一个个参数对象
34 // Extend the base object
35 for ( name in options ) {
36 src = target[ name ];
37 copy = options[ name ];
38
39 // Prevent never-ending loop
40 //防止自引用
41 if ( target === copy ) {
42 continue;
43 }
44
45 // Recurse if we're merging plain objects or arrays
46 //深拷贝
47 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
48 if ( copyIsArray ) {//被拷贝属性值是个数组
49 copyIsArray = false;
50 clone = src && jQuery.isArray(src) ? src : [];
51
52 } else {
53 clone = src && jQuery.isPlainObject(src) ? src : {};
54 }
55
56 // Never move original objects, clone them
57 //递归拷贝
58 target[ name ] = jQuery.extend( deep, clone, copy );
59
60 // Don't bring in undefined values
61 } else if ( copy !== undefined ) {//浅拷贝,属性值不是自定义
62 target[ name ] = copy;
63 }
64 }
65 }
66 }
67
68 // Return the modified object
69 return target;
70 };

【jQuery源码】整体架构的更多相关文章

  1. jquery源码 整体架构

    一.对外提供接口 对外提供了jQuery. //可以通过jQuery或者$来找到jQuery (function(window,undefined){ //(21,94) 定义了一些变量和函数 jQu ...

  2. jquery源码分析(二)——架构设计

    要学习一个库首先的理清它整体架构: 1.jQuery源码大致架构如下:(基于 jQuery 1.11 版本,共计8829行源码)(21,94)                定义了一些变量和函数jQu ...

  3. jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究

    终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...

  4. jQuery源码整体结构(源码2.0.3)

    拨开jQuery的面纱,最近了解了下jQuery源码整体框架.主要包括: (1)  jQuery 核心模块 (2)  sizzle 选择器引擎 (3)  Deferred 异步队列 (4)  Supp ...

  5. jQuery源码分析学习--资料收集--更新中

    1.逐行分析jQuery源码的奥秘 - 网易云课堂  http://study.163.com/course/courseMain.htm?courseId=465001#/courseDetail? ...

  6. jQuery 源码解析一:jQuery 类库整体架构设计解析

    如果是做 web 的话,相信都要对 Dom 进行增删查改,那大家都或多或少接触到过 jQuery 类库,其最大特色就是强大的选择器,让开发者脱离原生 JS 一大堆 getElementById.get ...

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

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

  8. jQuery源码分析-01总体架构

    1. 总体架构 1.1自调用匿名函数 self-invoking anonymous function 打开jQuery源码,首先你会看到这样的代码结构: (function( window, und ...

  9. js菜鸟进阶-jQuery源码分析(1)-基本架构

    导读: 本人JS菜鸟一枚,为加强代码美观和编程思想.所以来研究下jQuery,有需要进阶JS的同学很适合阅读此文!我是边看代码(jquery2.2.1),边翻“javascript高级程序设计”写的, ...

随机推荐

  1. Step by Step Guide on Yanhua ACDP Clear BMW EGS ISN

    Yanhua Mini ACDP authorize new function on BMW EGS ISN clearing.So here UOBDII want to share this st ...

  2. 用TSQL从sqlserve 发布订阅链中删除一张或几张表

    一个简单的存储过程,用来实现从一个SQLSERVE 发布订阅链中删除一张或几张表. /* 1.停日志读取代理 2.exec usp_从复制订阅中删除表 'dbtestPub','test1' 3.开日 ...

  3. 20165213Java第二次实验

    实验二Java面向对象程序设计 实验1 实验目的与要求: 参考http://www.cnblogs.com/rocedu/p/6371315.html#SECUNITTEST 完成单元测试的学习 提交 ...

  4. Redhat/Centos6.x安装Chrome

    由于Chrome对rhel6.x不在支持发布版本,只能安装chromium版本! 01.下载地址 http://people.centos.org/hughesjr/chromium/6/x86_64 ...

  5. Mybatis的针对于同一个有自己父类或子类的递归查询 (如商品分类)

    1.pojo代码 private Integer categoryId; private Integer superId; private String name; private Byte leve ...

  6. ECharts初体验

    ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等) ...

  7. Linux下nautilus的右键快捷菜单项设置

    某一天我的Linux更新完后, 我照常在文件夹下点击右键想打开终端, 却发现右键快捷菜单没有Open in terminal的菜单项了. 在网上查找了一下, 结合自己系统的情况发现了解决办法. 由于我 ...

  8. 可遇不可求的Question之MySQL系统变量interactive_timeout 与 wait_timeout 篇

    mysql>show variables like '%timeout'; 打印结果如下: +----------------------------+-------+ | Variable_n ...

  9. Alpha 冲刺(1)

    Alpha 冲刺 (1/10)   Part.1 开篇 队名:彳艮彳亍团队 组长博客:戳我进入 作业博客:班级博客本次作业的链接 Part.2 成员汇报 组员1(组长)柯奇豪 过去两天完成了哪些任务 ...

  10. MFC 多窗口通信时,使用RadioButton和Button时冲突问题

    最近项目需要我们实现在两个窗口间进行通信,其中有个小功能如图所示: 当我点击GDIProgram中的Button1时,会更新Dialog的Radio1和Radio2的状态. Dialog中的Radio ...