JQuery源码解析(一)

jQuery使用户能更方便地处理DOM、事件、实现动画效果,并且方便地为网站提供AJAX交互。

2、jQuery的模块依赖网:

jQuery一共13个模块,模块不是单一的,比如jQuery动画,都会依赖异步队列、动画队列、回调队列与数据缓存模块等。

jQuery抽出了所有可复用的特性,分离出单一模块,通过组合的用法,不管在设计思路与实现手法上jQuery都是非常高明的。

五大块:选择器、DOM操作、事件、AJAX与动画

那么为什么有13个模块?因为jQuery的设计中最喜欢的做的一件事,就是抽出共同的特性使之“模块化”,

当然也是更贴近S.O.L.I.D五大原则的“单一职责SRP”了,遵守单一职责的好处是可以让我们很容易地来维护这个对象,

比如,当一个对象封装了很多职责的时候,一旦一个职责需要修改,势必会影响该对象的其它职责代码。

通过解耦可以让每个职责更加有弹性地变化。
我们来看看jQuery文档针对业务层的Ajax的处理提供了一系列的门面接口:

.ajaxComplete()
.ajaxError()
.ajaxSend()
.ajaxStart()
.ajaxStop()
.ajaxSuccess()

底层接口:

jQuery.ajax()
jQuery.ajaxSetup()

快捷方法:

jQuery.get()
jQuery.getJSON()
jQuery.getScript()
jQuery.post()

jQuery接口的设计原理

业务逻辑是复杂多变的,jQuery的高层API数量非常多,而且也非常的细致,这样做可以更友好的便于开发者的操作,

不需要必须在一个接口上重载太多的动作。我们在深入内部看看Ajax的高层方法其实都是统一调用了一个静态的jQuery.ajax方法,

代码见右侧代码编辑器(27-43行)。
在jQuery.ajax的内部实现是非常复杂的,首先ajax要考虑异步的处理与回调的统一性,

所以就引入了异步队列模块(Deferred)与回调模块(Callbacks), 所以要把这些模块方法在ajax方法内部再次封装成、

构建出一个新的jQXHR对象,针对参数的默认处理,数据传输的格式化等等。

二:立即调用表达式

任何库与框架设计的第一个要点就是解决命名空间与变量污染的问题。

jQuery就是利用了JavaScript函数作用域的特性,采用立即调用表达式包裹了自身的方法来解决这个问题。

jQuery的立即调用函数表达式的写法有三种:

写法1:

(function(window, factory) {
    factory(window)
}(this, function() {
    return function() {
       //jQuery的调用
    }
}))

可以看出上面的代码中嵌套了2个函数,而且把一个函数作为参数传递到另一个函数中并且执行,这种方法有点复杂,我们简化一下写法:

写法2:

var factory = function(){
    return function(){
        //执行方法
    }
}
var jQuery = factory();

上面的代码效果和方法1是等同的,但是这个factory有点变成了简单的工厂方法模式,需要自己调用,不像是一个单例的jQuery类,所以我们需要改成“自执行”,而不是另外调用。

写法3:

(function(window, undefined) {
    var jQuery = function() {}
    // ...
    window.jQuery = window.$ = jQuery;
})(window);

从上面的代码可看出,自动初始化这个函数,让其只构建一次。详细说一下这种写法的优势:

1、window和undefined都是为了减少变量查找所经过的scope作用域。当window通过传递给闭包内部之后,

在闭包内部使用它的时候,可以把它当成一个局部变量,显然比原先在window scope下查找的时候要快一些。
  2、undefined也是同样的道理,其实这个undefined并不是JavaScript数据类型的undefined,而是一个普普通通的变量名。

只是因为没给它传递值,它的值就是undefined,undefined并不是JavaScript的保留字。

为什么要传递undefined?

Javascript 中的 undefined 并不是作为关键字,因此可以允许用户对其赋值。

var undefined = ‘孙丽媛‘ ;(function(window) { alert(undefined);//IE8 ‘孙丽媛‘ })(window)

IE8存在这个问题,当然,大部分浏览器都是不能被修改的

如果函数调用不传递,参数默认就是undefined

;(function(window,undefined) {
    //undefined
})(window)

jQuery为什么要创建这样的一个外层包裹,其原理又是如何?

这里要区分2个概念一个是匿名函数,一个是自执行。顾名思义,匿名函数,就是没有函数名的函数,也就是不存在外部引用。但是是否像下面代码实现呢:

function(){
//代码逻辑
}

上面这种写法是错了,声明了它但是又不给名字又没有使用,所以在语法上错误的,那么怎么去执行一个匿名的函数呢?
要调用一个函数,我们必须要有方法定位它、引用它。所以,我们要取一个名字:

var jQuery = function(){
//代码逻辑
}

jQuery使用()将匿名函数括起来,然后后面再加一对小括号(包含参数列表),那么这小括号能把我们的表达式组合分块,

并且每一块(也就是每一对小括号),都有一个返回值。这个返回值实际上也就是小括号中表达式的返回值。

所以,当我们用一对小括号把匿名函数括起来的时候,实际上小括号返回的,就是一个匿名函数的Function对象。

因此,小括号对加上匿名函数就如同有名字的函数般被我们取得它的引用位置了。

所以如果在这个引用变量后面再加上参数列表,就会实现普通函数的调用形式。

最后,我们回到写法1看看jQuery利用写法3的写法,然后把整个函数作为参数传递给另外一个函数,

主要是为了判断jQuery在不同平台的下的加载逻辑,主流的库一般都有对 AMD 和 CommonJS 的支持代码,看看jQuery的代码:

if (typeof module === "object" && typeof module.exports === "object") {
    module.exports = global.document ?
        factory(global, true) :
        function(w) {
            if (!w.document) {
                throw new Error("jQuery requires a window with a document");
            }
            return factory(w);
    };
} else {
    factory(global);
}

总结:全局变量是魔鬼, 匿名函数可以有效的保证在页面上写入JavaScript,而不会造成全局变量的污染,

通过小括号,让其加载的时候立即初始化,这样就形成了一个单例模式的效果从而只会执行一次。

时间: 2024-08-15 13:41:50

JQuery源码解析(一)的相关文章

五.jQuery源码解析之jQuery.extend(),jQuery.fn.extend()

给jQuery做过扩展或者制作过jQuery插件的人这两个方法东西可能不陌生.jQuery.extend([deep],target,object1,,object2...[objectN]) jQuery.fn.extend([deep],target,object1,,object2...[objectN])这两个属性都是用于合并两个或多个对象的属性到target对象.deep是布尔值,表示是否进行深度合并,默认是false,不执行深度合并.通过这种方式可以在jQuery或jQuery.fn

十三.jQuery源码解析之$.type()

512行:出现了一个class2type. 在jQuery中全局搜索这个变量. 这段代码的意思是将一串字符串通过空格分割成数组,并且使用each遍历数组来初始化class2type. 最终的结果应该是这样的. { "[object Array]":"array", "[object Boolean]":"boolean", "[object Date]":"date", "[o

四.jQuery源码解析之jQuery.fn.init()的参数解析

从return new jQuery.fn.init( selector, context, rootjQuery )中可以看出 参数selector和context是来自我们在调用jQuery方法时传过来的.那么selector和context都有哪些可能. 对于表格中的4~9行中的可能做具体分析. 如果selector是字符串,则首先检测是html代码还是#id. 126行的if语句:以"<"开头,以">"结尾,且长度>=3.则假设额这个是HT

二.jQuery源码解析之构建jQuery之构建函数jQuery的7种用法

一:$(selectorStr[,限制范围]),接受一个选择器(符合jQuery规范的字符串),返回一个jQuery对象;二:$(htmlStr[,文档对象]),$(html[,json对象])传入html字符串,创建一个新的dom元素 三:$(dom元素),$(dom元素集合)将dom元素转换成jQuery对象.四:$(自定义对象)封装普通对象为jQuery对象.五:$(回调函数)绑定ready事件监听函数,当Dom加载完成时执行.六:$(jQuery对象)接受一个jQuery对象,返回一个j

八.jQuery源码解析之get()

理论上get是用来返回jQuery对象中部分或全部元素为数组的,但是转换为数组后,数组中的单个元素又是一个一个dom元素.所以get还有另外一个功效,就是将jQuery对象转换成dom对象.如果get中的参数为空了,则直接调用toArray();如果参数小于0,则表示从元素后面开始计算,如果num>0表示直接返回指定位置的元素. 八.jQuery源码解析之get(),布布扣,bubuko.com

jquery源码解析:代码结构分析

本系列是针对jquery2.0.3版本进行的讲解.此版本不支持IE8及以下版本. (function(){ (21, 94)     定义了一些变量和函数,   jQuery = function(){}; (96,283)   给jQuery对象添加一些属性和方法(实例方法,通过$("div")这类的jQuery实例对象来调用) (285,347)   extend : jQuery的继承方法 (349,817)   jQuery.extend():扩展一些工具方法(静态方法,直接通

十七.jQuery源码解析之入口方法Sizzle(1)

函数Sizzle(selector,context,results,seed)用于查找与选择器表达式selector匹配的元素集合.该函数是选择器引擎的入口. 函数Sizzle执行的6个关键步骤如下: 1.解析选择器表达式,解析出块表达式和关系符. 2.如果存在位置伪类,则从左向右查找: a.查找第一个块表达式匹配的元素集合,得到第一个上下文元素集合. b.遍历剩余的块表达式和块间关系符,不断缩小上下文元素集合. 3.否则从右向左查找: a.查找最后一个块表达式匹配的元素集合,得到候选集,映射集

十五.jQuery源码解析之Sizzle总体结构.htm

Sizzle是一款纯javascript实现的css选择器引擎,它具有完全独立,无库依赖;小;易于扩展和兼容性好等特点. W3C Selectors API规范定义了方法querySelector()和querySelectorAll(),但是IE6,7不支持这两个方法. 在Sizzele内部,如果浏览器支持方法querySelectorAll(),则调用该方法查找元素,如果不支持,则模拟该方法的行为. Sizzle支持几乎所有的css3选择器,并且会按照文档位置返回结果. 上面截取的只是Siz

十六.jQuery源码解析之Sizzle设计思路.htm

为了便于后面的叙述,需要了解一些相关术语和约定. 并列选择器表达式:"div,p,a"====>div,p,a是并列的. 块表达式:"div>p"中的div和p就是两个块. 块表达式的类型:共8种.id,class,name,attr,tag,child,pos,pseudo(伪类表达式) 块间的关系符:共4种.">":父子关系,"+":紧挨着的兄弟关系,"~":后面的所有兄弟关系,&qu

十二.jQuery源码解析之.eq().first().last().slice()

eq(index):将集合中的索引为index的元素提取出来. first():返回集合中的第一个元素. .last():防护集合中的最后一个元素. .slice(start[,end]):返回集合中的给定区间段的元素. first()和last()调用eq(),eq()通过slice()实现,slice()通过 .pushStack()实现. 相关源码 285行:用法很奇特,通过一个"+"把可能为字符串的i转换成一个数值. 300~301:先借用数组方法slice()从当前jQuer