jQuery源代码 框架分析

每个框架都有一个核心。全部的结构都是基于这个核心之上,结构建立好了之后,剩下的就是功能的堆砌。

jQuery的核心就是从HTML文档中匹配元素并对其操作。

就跟一座大楼一样。让我们一步一步了解这座大厦的基石和结构。

1.构造函数

2.链式语法

3.选择器

4.扩展性

 一、构造函数

  我们知道类是面向对象编程的一个重要概念。它是对事物的最高抽象。它是一个模型。通过实例化一个类,我们能够创建一个实例。

javascript本身没有类的概念。仅仅有原型prototype。prototype是什么呢?它是为构造函数设置的一个属性。这个属性包括一 个对象(简称prototype对象)。这个对象中包括了实例对象共享的属性(properties)和方法(methods)。有了这么一个属性,我们 就能够让全部的实例共享某些东西,来实现面向对象中类的概念。

以下用一个样例来解释一下。链接--------------

因此jQuery利用原型继承来实现类的

 1 var jQuery = function(){}
 2
 3 jQuery.prototype = {
 4     //扩展的原型对象
 5 }
 6 //因为prototype名称太长。我们能够另起一名fn
 7 jQuery.fn = jQuery.prototype = {
 8     //扩展的原型对象
 9 }
10 /********************我是切割线************************/
11 //同理jQuery也能够用别名$来取代。因此代码能够写成
12 var $ = jQuery = function(){};
13 jQuery.fn = jQuery.prototype = {
14     //扩展的原型对象
15     jquery : "1.7.2",
16     size : function(){
17         return this.length;
18     }
19 }

那我们怎样调用它吗?

1 var my$ = new $();//实例化
2 console.log(my$.jquery);//1.7.2
3 console.log(my$.size());//undefined

可是jQuery并非这么调用的,它类似$().jquery 这样的形式。

也就是说jQuery没用new实例化,而是直接调用jQuery()函数,然后后面跟jQuery的原型方法。

怎么实现呢?

 1 var $ = jQuery = function(){
 2     return  new jQuery();
 3 };
 4 jQuery.fn = jQuery.prototype = {
 5
 6     jquery : "1.7.2",
 7     size : function(){
 8         return this.length;
 9     }
10 }
11
12 console.log($().jquery);
13 console.log($().size());

假设依照上面的做法会出错,内存溢出。由于创建实例的时候循环引用导致出错。

我们须要返回一个实例,我们知道在new一个对象的时候。this指向new的实例,实例获取了prototype的属性方法。

因此我们能够用工厂方法创建一个实例,把这种方法放在jQuery.prototype 的原型对象其中,然后在jQuery函数中返回这个原型方法的调用。

 1 var $ = jQuery = function(){
 2     return  jQuery.fn.init();
 3 };
 4 jQuery.fn = jQuery.prototype = {
 5     init: function(){
 6         console.log(this);
 7         return this;//返回实例的引用
 8     },
 9     jquery : "1.7.2",
10     size : function(){
11         return this.length;
12     }
13 }
14 console.log($().jquery);
15 console.log($().size());

console中会看到this对象是 jQuery的一个实例。

init()方法返回的是thiskeyword,该keyword引用的是jQuery的实例。假设在init()中继续使用thiskeyword,也就是将init函数视为一个构造器,this又是怎样处理呢?

var $ = jQuery = function(){
    return  jQuery.fn.init();
};
jQuery.fn = jQuery.prototype = {
    init: function(){
        this.length = 2;
        this.test = function(){
            return this.length;
        }
        return this;
    },
    jquery : "1.7.2",
    length:0,
    size : function(){
        return this.length;
    }
}

console.log($().jquery);
console.log($().test()); //2 ?

0 ?

console.log($().size()); //2 ?

0 ?

  返回的都是2,能够看到,thiskeyword引用了init函数作用域所在的对象,此时它訪问length属性时,返回的为2。thiskeyword也能訪问上级对象jQuery.fn对象的作用域,所以返回1.7.2,而调用size方法时,返回的是2而不是0。

这样的设计思路非常easy破坏作用域的独立性,对jQuery框架可能产生消极影响,因此jQuery通过实例化init初始化类型来切割作用域的

1 var $ = jQuery = function(){
2     return new jQuery.fn.init();
3 };    

  这样就能够把init()构造函器中的this和jQuery.fn对象中的thiskeyword隔离开来。

避免混淆。可是这样的方法带来的还有一个问题是无法訪问jQuery.fn 的对象的属性和方法。

Object [object Object] has no method ‘size‘.

怎样做到既能切割初始化构造函数与jQuery原型对象的作用域,又可以在返回实例中訪问jQuery原型对象呢?

jQuery框架巧妙地通过原型传递攻克了这个问题

1 jQuery.fn.init.prototype = jQuery.fn;//使用jQuery原型对象覆盖init原型对象

  这样 new jQuery.fn.init() 创建的新对象拥有init构造器的prototype原型对象的方法,通过改变prototype指针的指向,使其指向jQuery类的prototype,这样创造出来的对象就继承了jQuery.fn原型对象定义的方法。

 二、扩展性

  jQuery 自己定义扩展方法用的extend () 函数

1 jQuery.extend = jQuery.fn.extend = function() {
2     //code
3 }

在讲源代码之前,先说一下什么是拷贝,浅拷贝。深拷贝。

我们知道js 种不同的数据类型

基本类型:按值传递  (undefined,NULL,boolean,String,Number)

引用类型:传递内存地址 Object

/* 深度拷贝,全部的元素和属性全然clone,并与原引用对象全然独立。克隆后的对象与原对象再也没有不论什么关系。也就是当你拷贝完毕后。原对象值有不论什么更改。都不会影响到我们克隆后那个对象的值*/

所以我们在进行深拷贝(clone)的时候。注意将复制对象中的每个值,而不是引用。换句话说。就是採用递归的方法浅拷贝对象。

1.浅拷贝

 1 var clone = _.clone = function(obj){
 2     //不是对象直接放回返回值
 3     if (typeof obj != ‘object‘) return obj;
 4     var result;
 5     //数组用slice方法 不改变原数组
 6     if(Object.prototype.toString.call(obj)==="[Object Array]"){
 7         result =  obj.slice();
 8     }else{
 9         //对象 for遍历
10         result = {};
11         for(var name in obj){
12             result[name] = object[name];
13         }
14     }
15     return result;
16 }

2.深拷贝

 1 var _deepClone = function(source){
 2     if(source===null) return null;
 3     var result;
 4     if(source instanceof Array){
 5         result = [];
 6         //假设是数组,递归调用
 7         for(var i = 0;i<source.length;i++){
 8             result[i] = _deepClone(source[i]);
 9         }
10         return result;
11     }else if(source instanceof Object){
12         //假设是对象,递归调用
13         result = {};
14         for(var name in source){
15             result[name] = _deepClone(source[name]);
16         }
17         return result;
18     }
19     else{
20         //假设都不是就返回值
21         return source;
22     }
23 };

3.jQuery 的实现

 1 jQuery.extend = jQuery.fn.extend = function() {
 2     //全部使用的的变量最好最好在函数定义的最前就写下来。原因与ECMA有关 具体解释
 3
 4     var options, name, src, copy, copyIsArray, clone,
 5         target = arguments[0] || {},
 6         i = 1,
 7         length = arguments.length,
 8         deep = false;
 9
10     // 推断是否为深拷贝|浅拷贝
11     if ( typeof target === "boolean" ) {
12         deep = target;
13         target = arguments[1] || {};    //返回的目标对象
14         // 遍历的时候跳过 deep | target 參数
15         i = 2;
16     }
17
18     // 假设初始值不为对象 且不是一个函数则置空,比方一个string ""置为{};
19     if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
20         target = {};
21     }
22
23     // 假设仅仅有自己一个參数,而没有被克隆继承的參数。则返回自己本身
24     if ( length === i ) {
25         target = this;
26         --i;
27     }
28
29     for ( ; i < length; i++ ) {
30         // 处理值为null undefined情况
31         if ( (options = arguments[ i ]) != null ) {
32             // 继承对象options
33
34             for ( name in options ) {
35                 src = target[ name ];       //原对象中相应的值
36                 copy = options[ name ];     //须要拷贝的对象中相应的值
37
38                 // 防止陷入死循环。假设原对象本身就等于须要拷贝的对象中的那值(o),
            //在对o遍历的时候就把自己又一次遍历赋值了一遍
39                 if ( target === copy ) {
40                     continue;
41                 }
42
43                 //在 Array和Object的情况。且deep为true和传进对象有值(true)的情况下。递归调用本身方法进行深拷贝
44                 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
45                     if ( copyIsArray ) {//假设须要拷贝的对象为数组
46                         copyIsArray = false;
47                         clone = src && jQuery.isArray(src) ?

src : [];
48
49                     } else {
50                         clone = src && jQuery.isPlainObject(src) ? src : {};
51                     }
52
53                     target[ name ] = jQuery.extend( deep, clone, copy );
54                     // 假设不是上述情况,则进行浅拷贝,我们在运行jQuery.extend({})或jQuery.fn.extend({})的时候都是运行的这种方法,但却搞不明确为什么一个是对JQuery类的自己定义扩展。一个是JQuery对象的自己定义扩展。那么这里的target到底代表什么呢。我们看以下的样例
55                 } else if ( copy !== undefined ) {
56                     target[ name ] = copy;
57                 }
58             }
59         }
60     }
61
62     // 返回改动过后的target
63     return target;
64 };

注意:尽管jQuery.extend = jQuery.fn.extend 它们是一个方法。可是它们的详细作用是不一样的,由于this的指向不同。

	function jQuery() {}
	//使用字面量的方式创建原型对象,这里{}就是对象,是Object,new Object就相当于{}
	jQuery.fn = jQuery.prototype = {
		constructor : jQuery,			//强制指向jQuery
		name : ‘Lee‘,
		age : 100,
		run : function () {
			return this.name + this.age + ‘执行中...‘;
		}
	};
	jQuery.extend = jQuery.fn.extend = function(){
		var option = arguments[0] ;
		for(var v in option){
			this[v] = option[v];
		}
		return this;
	};
	var jquery = new jQuery();
	document.write("<p style=‘color:blue‘>"+jQuery.extend({
			add:function(){
				alert("aaaa");
			}
		})+"</p>");
	document.write("<p style=‘color:blue‘>"+jQuery.fn.extend({
			minu:function(){
				alert("bbbb");
			}
		})+"</p>");	

	jQuery.add();
	jquery.minu();

this打印结果

function jQuery() {}

[object Object]

在构造函数那个模块我们看到

jQuery .extend 的this 是jQuery类本身。在jQuery类上加入(对象。方法)

jQuery.fn.extend 的this是jQuery的原型,在jQuery原型上加入(对象,方法),那么JQuery对象本身也会具有哪些方法

jQuery.fn = jQuery.prototype

四、来一个简化版的

 1 var _deepClone = function(source){
 2     if(source===null) return null;
 3     var result;
 4     if(source instanceof Array){
 5         result = [];
 6         //假设是数组。递归调用
 7         for(var i = 0;i<source.length;i++){
 8             result[i] = _deepClone(source[i]);
 9         }
10         return result;
11     }else if(source instanceof Object){
12         //假设是对象。递归调用
13         result = {};
14         for(var name in source){
15             result[name] = _deepClone(source[name]);
16         }
17         return result;
18     }
19     else{
20         return source;
21     }
22 };

时间: 2024-10-15 20:51:17

jQuery源代码 框架分析的相关文章

CDT源代码框架分析改造 线程对象的改造(三)

需求:当Debug系统上点击了停止跟踪后,如果缓存桢个数不为零,则默认显示第一桢的基本信息(跟踪点的id,线程id.等) 添加停止跟踪事件,这部分机制后面说.ICDIStopTraceEvent. CThread对象实现了ICDIEventListener接口,因此在出发停止跟踪事件的时候.该类的handleDebugEvents方法会拦截到此命令. 在CDT中,每个调试对象都有一个表现层跟CDT层的对象 例如线程对象. CThread对象位于eclipse的core包中.它通过getCDITh

CDT源代码框架分析改造 线程对象的改造 添加标签 区分断点跟跟踪点

cdt 到debug 通信路线 CBreakpointManager类中 protected void setBreakpointsOnTarget0( ICBreakpoint[] breakpoints ) { //添加标示符 String pointtype =breakpoint.getPointType(); fileName = convertPath(fileName).toOSString(); ICDIFunctionLocation location = cdiTarget.

jQuery框架分析第一章: 第一个匿名函数

我的jQuery版本为1.7* 这个版本代码比之前的版本优化了很多,结构也清晰了不少,就用最新的吧. 打开jQuery源代码 首先你能看到所有代码被一个 (function(window,undefined){ })(window) 这是个什么东西.. 首先,这是一个匿名函数(不懂?那就先去谷歌下吧): 其次,这是一个自调用匿名函数: 这段代码做了三件事 第一件:创建一个只给jQuery用的空间,我们估且就叫 “私有空间”,与C++的命名空间很相似,为了保证jQuery不与其他JavaScrip

jQuery源码 框架分析

每一个框架都有一个核心,所有的结构都是基于这个核心之上,结构建立好了之后,剩下的就是功能的堆砌. jQuery的核心就是从HTML文档中匹配元素并对其操作. 就跟一座大楼一样,让我们一步一步了解这座大厦的基石和结构. 1.构造函数 2.链式语法 3.选择器 4.扩展性  一.构造函数 我们知道类是面向对象编程的一个重要概念,它是对事物的最高抽象,它是一个模型.通过实例化一个类,我们可以创建一个实例. javascript本身没有类的概念,只有原型prototype,prototype是什么呢?它

《Android系统源代码情景分析》连载回忆录:灵感之源

上个月,在花了一年半时间之后,写了55篇文章,分析完成了Chromium在Android上的实现,以及Android基于Chromium实现的WebView.学到了很多东西,不过也挺累的,平均不到两个星期一篇文章.本来想休息一段时间后,再继续分析Chromium使用的JS引擎V8.不过某天晚上,躺在床上睡不着,鬼使神差想着去创建一个个人站点,用来连载<Android系统源代码情景分析>一书的内容. 事情是这样的,躺在床上睡不着,就去申请了一个域名,0xcc0xcd.com.域名申请到了,总不能

jQuery源代码学习之六——jQuery数据缓存Data

一.jQuery数据缓存基本原理 jQuery数据缓存就两个全局Data对象,data_user以及data_priv; 这两个对象分别用于缓存用户自定义数据和内部数据: 以data_user为例,所有用户自定义数据都被保存在这个对象的cache属性下,cache在此姑且称之为自定义数据缓存: 自定义数据缓存和DOM元素/javascript对象通过id建立关联,id的查找通过DOM元素/javascript元素下挂载的expando属性获得 话不多说,直接上代码.相关思路在代码注释中都有讲解

Android Bitmap 开源图片框架分析(精华三)

主要介绍这三个框架,都挺有名的,其他的框架估计也差不多了 Android-Universal-Image-Loaderhttps://github.com/nostra13/Android-Universal-Image-Loader ImageLoaderhttps://github.com/novoda/ImageLoader Volley(综合框架,包含图片部分)https://github.com/mcxiaoke/android-volley 扯淡时间,可以跳过这段这些开源框架的源码还

Android Bitmap 开源图片框架分析(精华四)

disk缓存主要难点在于内存缓存,disk缓存其实比较简单,就是图片加载完成后把图片文件存到本地方便下次使用 同样,先贴一下官方主页的介绍(主页地址见文章最开始处)和内存缓存差不多,根据算法不同提供了几种类别,可以自行通过ImageLoaderConfiguration.discCache(..)设置<ignore_js_op> 硬盘缓存,保存是以文件的形式框架提供了4种类型,具体算法规则不同,看名字我们大概也能知道对应意思 UnlimitedDiscCache                

TI BLE协议栈软件框架分析

看源代码的时候,一般都是从整个代码的入口处开始,TI  BLE 协议栈源码也不例外.它的入口main()函数就是整个程序的入口,由系统上电时自动调用. 它主要做了以下几件事情: (一)底层硬件初始化配置 (二)创建任务并初始化任务配置 (三)检测并执行有效的任务事件 Main() 函数源码如下: 一:底层硬件初始化设置 75行,设置系统时钟,使能内存缓冲功能. 78行,关中断,刚启动时,系统运行不稳定,一般会首先关中断. 81行,硬件相关的I/O 口配置. 84行,初始化mcu 内部的flash