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

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 };

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

  1. jQuery源代码框架思路

    開始计划时间读源代码,第一节jQuery框架阅读思路整理 (function(){ jQuery = function(){}; jQuery一些变量和函数和给jQuery对象加入一些方法和属性 ex ...

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

    我的jQuery版本为1.7* 这个版本代码比之前的版本优化了很多,结构也清晰了不少,就用最新的吧. 打开jQuery源代码 首先你能看到所有代码被一个 (function(window,undefi ...

  3. 三元表达式之理解/jquery源代码分析之$.inArray实现

    每次看到三元表达式就会惶惶然分不清怎样读,正如语文中的断句一样,jquery源代码中的三元表达式更是不知怎样断句. 附jquery中的inArray实现. 大家熟悉jquery的应该都不陌生inArr ...

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

    上个月,在花了一年半时间之后,写了55篇文章,分析完成了Chromium在Android上的实现,以及Android基于Chromium实现的WebView.学到了很多东西,不过也挺累的,平均不到两个 ...

  5. jQuery异步框架探究1:jQuery._Deferred方法

    jQuery异步框架应用于jQuery数据缓存模块.jQuery ajax模块.jQuery事件绑定模块等多个模块,是jQuery的基础功能之中的一个.实际上jQuery实现的异步回调机制能够看做ja ...

  6. 几款开源的hybird移动app框架分析

    几款开源的Hybrid移动app框架分析 Ionic Onsen UI 与 ionic 相比 jQuery Mobile Mobile Angular UI 结论 很多移动开发者喜欢使用原生代码开发, ...

  7. jQuery源代码学习之九—jQuery事件模块

    jQuery事件系统并没有将事件坚挺函数直接绑定在DOM元素上,而是基于事件缓存模块来管理监听函数的. 二.jQuery事件模块的代码结构 //定义了一些正则 // // //jQuery事件对象 j ...

  8. jQuery源代码学习之八——jQuery属性操作模块

    一.jQuery属性模块整体介绍 jQuery的属性操作模块分四个部分:html属性操作,dom属性操作,类样式操作,和值操作. html属性操作(setAttribute/getAttribute) ...

  9. jQuery源代码学习之七—队列模块queue

    一.jQuery种的队列模块 jQuery的队列模块主要是为动画模块EFFECTS提供支持,(不过到现在为了支持动画队列的inprogress的出入队还是搞不太清楚),单独抽取出一个命名空间是为了使程 ...

随机推荐

  1. 负载平衡(cogs 741)

    «问题描述:G 公司有n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使n 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运.«编程任务:对于给定的n 个环 ...

  2. POJ3104 Drying

    Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 13703   Accepted: 3527 Description It i ...

  3. configurationmanager.getsection usage

    public static void CreateAppSettings() { // Get the application configuration file. System.Configura ...

  4. transform与position:fixed的那些恩怨

    1. 前言 在写这篇文章之前,我理解的fixed元素是这样的:(摘自CSS布局基础) 固定定位与absolute定位类型类似,但它的相对移动的坐标是视图(屏幕内的网页窗口)本身.由于视图本身是固定的, ...

  5. ubuntu 15.10 64bit 下 steam无法启动

    首先查看steam日志,在/tmp/dumps/下,以“用户名_output.txt”命名. $ cat /tmp/dumps/liuxu_output.txt Running Steam on ub ...

  6. C#图解教程学习笔记——事件

    一.事件的定义事件:当一个特定的程序事件发生时,程序的其他部分可以得到该事件已经发生的通知,同时运行相应处理程序.事件的很多部分都与委托类似.实际上,事件就像专门用于特殊用途的简单委托.事件包含了一个 ...

  7. ASP.NET MVC验证所有属性是否合法

    1.实现代码: /// <summary> /// 验证所有属性是否合法 /// </summary> /// <param name="modelState& ...

  8. luogu P1608 路径统计

    题目描述 “RP餐厅”的员工素质就是不一般,在齐刷刷的算出同一个电话号码之后,就准备让HZH,TZY去送快餐了,他们将自己居住的城市画了一张地图,已知在他们的地图上,有N个地方,而且他们目前处在标注为 ...

  9. 寒假week1---二分查找(二分枚举)

    寒假week1---二分查找(二分枚举)1.适用条件:要查找(枚举)的集合有序 && 查找(枚举)的“条件”具有单调性2.什么是“条件”:example: 1.给定一个有序数组,从中查 ...

  10. 2016集训测试赛(二十)Problem A: Y队列

    Solution 考虑给定一个\(n\), 如何求\(1\)到\(n\)的正整数中有多少在队列中. 不难注意到我们只需要处理质数次方的情况即可, 因为合数次方会被其因数处理到. 同时我们考虑到可能存在 ...