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. jquery.validate.js的简单示例

    一.官方资料 官网 github 二.html <!DOCTYPE html> <html> <head> <meta charset="utf-8 ...

  2. LB+ECS+RDS经典架构图例及注意事项

    LB+ECS+RDS经典架构图例及注意事项

  3. 2019.02.26 bzoj4311: 向量(线段树分治+凸包)

    传送门 题意: 支持插入一个向量,删去某一个现有的向量,查询现有的所有向量与给出的一个向量的点积的最大值. 思路: 考虑线段树分治. 先对于每个向量处理出其有效时间放到线段树上面,然后考虑查询:对于两 ...

  4. ABP框架系列之三十一:(Localization-本地化)

    Introduction Any application has at least one language for user interface. Many applications have mo ...

  5. drf8 解析器

    解析器的介绍 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己想要的数据类型的过程. 本质就是对请求体中的数据进行解析. Accept与ContentType请求头. Accept是告诉 ...

  6. Spring AOP中pointcut expression表达式

    Pointcut 是指那些方法需要被执行"AOP",是由"Pointcut Expression"来描述的. Pointcut可以有下列方式来定义或者通过&am ...

  7. Alpha冲刺 - (7/10)

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

  8. C语言小程序——推箱子(窄字符和宽字符)

    C语言小程序——推箱子(窄字符Version) 推箱子.c #include <stdio.h> #include <conio.h> #include <stdlib. ...

  9. redis key的过期时间

    设置redis key的生存过期时间 Redis 有四个不同的命令可以用于设置键的生存时间(键可以存在多久)或过期时间(键什么时候会被删除) : EXPlRE 命令用于将键key 的生存时间设置为tt ...

  10. 生成多个git ssh密钥

    如果你已经有了一套名为 id_rsa 的公秘钥,将要生成另外一个公钥,比如 aysee ,你也可以使用任何你喜欢的名字. 步骤如下: 1.生成一个新的自定义名称的公钥: ssh-keygen -t r ...