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. zeromq学习记录(五)vc下多线程

    /************************************************************** 技术博客 http://www.cnblogs.com/itdef/   ...

  2. ----关于position的四个标签----

    从[ two1-4 ]分别为absolute,fixed,static,relative标签 四个标签下位移值相同,[ two2 ]和[ two1 ]都出现在左上角,[ two2 ] 盖住了[ two ...

  3. python3 安装 opencv (转)

    Python3支持pip方式自动安装第三方开发包,我们只要打开windows下面的命令行工具,输入如下命令: pip install opencv-python 安装最新的OpenCV3.3开发包 p ...

  4. vue里router-link标签设置动态路由的3个方法

    1.to绑定data里面的一个值 2.to绑定一个对象,用name 3.to绑定一个对象,用path 例子: <router-link :to="home"><s ...

  5. python闭包的详细解析

    一.什么是闭包? 如果一个内嵌函数访问外部嵌套函数作用域的变量,并返回这个函数,则这个函数就是闭包 闭包必须满足三个条件: 1. 必须有一个内嵌函数    2. 内嵌函数必须引用外部嵌套函数中的变量  ...

  6. Oracle实现like多个值的查询

    问题背景描述: 某天客户有一个需求,给定一批的手机号码或者电话号码,查询出相关的通话记录,以及相关的一些信息. 客户给定的被叫号码如图所示:   查询出来的结果如下图所示(本批次的结果不是上图导入的结 ...

  7. VS2015 类模板保存位置

    如果安装在C盘,则是如下位置: C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\ItemTemplates\CSharp ...

  8. postgresql vacuum操作

    postgresql vacuum操作 PostgreSQL数据库管理工作中,定期vacuum是一个重要的工作.vacuum的效果: 1.1释放,再利用 更新/删除的行所占据的磁盘空间. 1.2更新P ...

  9. Python自动化开发 - Python操作Memcached、Redis、RabbitMQ

    Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载. 它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速 ...

  10. uniGUI经验几则

    uniGUI经验几则 (2015-11-07 21:42:41) 转载▼ 标签: it 分类: uniGUI 1.uniTimer的妙用 很多时候,都会遇到在一个uniForm或者uniFrame加载 ...