若是是作 web 的话,相信都要对 Dom 进行增删查改,那你们都或多或少接触到过 jQuery 类库,其最大特点就是强大的选择器,让开发者脱离原生 JS 一大堆 getElementById、getElementsByName...官方提供超长方法 api 。javascript
jQuery 总体源码,本人也还在阅读中,暂时记录一下。(为何要看源码,缘由很简单---- 一 好好了解一下 jQuery 原理 二 为了装逼显摆)。css
一 使用 jQuery 时候,首先需引入 jQuery 文件,而以后,你们便可直接使用 $ 、jQuery 调用。为何呢?java
想必,写过 javascript 的同窗,都知道 window 是 top 对象,而像 document、location、navigator 等为 window 下属性,为了方便使用,能够省略 window. ,那么,jQuery 一样原理。jquery
在源码中 $、jQuery 一样是采用此种方法引入 window.$=window.jQuery=xxx。如图所示,图中页面引入了 jQuery 库。web
// Expose jQuery to the global object window.jQuery = window.$ = jQuery;
二 jQuery 库使用过程当中,通常使用两种形式,一种即为 $.ajax、$.noConflict ,另外一种则为 $(方法参数) 进行使用ajax
经过源码可知,jQuery 自己为一个 function ,而 $.ajax 、$.noConflict 能够视为该函数对象添加的静态方法,而使用的 $() 即至关于调用 $ 函数方法。api
jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init( selector, context, rootjQuery ); },
三 jQuery 源码中自执行函数做用,以及自执行函数中传入的 window 、undefined 的做用 ?函数
(function( window, undefined ) { ....... })(window);
自执行函数:自动执行该函数,用户在外面没法手动调用,且自执行一次。 自执行函数至关于建立了一个特殊的做用域,而该做用域封闭,避免污染全局变量。 如下仅列举两种常见写法。测试
( function (){this
函数体
})();
+ function A(){
函数体
}();
而在 jQuery 源中,方法传入了 window 、undefined 两个参数。
window:由于函数在调用时,其查找变量值时,需一级一级往上查找,若是当前函数做用域没有该变量,将会往上一级继续查找,直接传入 window ,可减小查找时间,提升效率。
undefined:经楼主测试在 IE 8 下, undefined 属性值可进行修改,此时传入参数undefined 应该时保持 undefined 初始值。
四 简谈 JavaScript 原型
原型:JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不只仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依此层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。简而言之,即在 JavaScript 中,任意对象的 __proto__ 属性 (原型)(而其值等于该对象构造函数的 prototype 属性 ,obj.__proto__===obj.constructor.prototype 。)
目前,也可经过 Object.getPrototypeOf( arg ) 方法获取对象原型,参数 arg 即为当前对象 .
Object.getPrototypeOf( obj)===obj.__proto__===obj.constructor.prototype。在 JS 中,即经过原型实现继承,当在该前对象的自身属性中查找不到相关方法属性,再往其 __proto__ 属性中查找,若是再查找不到,再往其 __proto__属性值的 __proto__一级一级往上查找,从而造成原型链,顶级的 Object.prototype.__proto__ 为 null,最终为止。
而在 jQuery 中,像使用的 jQuery.ajax 等方法可视为 jQuery 该函数对象(在 JS 中,任意都视为对象)拥有的静态方法 ,而相似 jQuery(参数).css() 等方法,可视为经过 jQuery 函数对象为构造器建立的对象,而其拥有的方法属性,则来自 jQuery.prototype 中(对象的 __proto__ 等于该对象的构造函数的 prototype 属性)。
五 jQuery 源码中原型使用
1 // 首先,在执行函数中定义 jQuery 变量,而 jQuery 变量为一个 function 。 2 jQuery = function( selector, context ) { 3 // 在 jQuery 函数体中 ,经过 new jQuery.fn.init 为构造器函数,返回新的对象。
经过上面原型原理可知,该建立对象的 __proto__ (原型)指向其构造函数的 prototype 属性 (jQuery.fn.init.prototype) 4 return new jQuery.fn.init( selector, context, rootjQuery ); 5 }, 6 7 // 将 jQuery 函数对象 prototype 属性另起别名 : jQuery.fn=jQuery.prototype
同时,将 jQuery.protype 从新赋值 ,将其 constructor 指向 jQuery 函数对象 ,新增 init 属性(一样,为一个函数对象,jQuery 函数体中就经过调用该方法建立对象),
还增长了一些属性及方法,好比:selector 、jQuery 、size 等方法属性 8 jQuery.fn = jQuery.prototype = { 9 constructor: jQuery, 10 init: function( selector, context, rootjQuery ){ 11 ..... 12 }, 13 // Start with an empty selector 14 selector: "", 15 16 // The current version of jQuery being used 17 jquery: "1.8.3", 18 19 // The default length of a jQuery object is 0 20 length: 0, 21 22 // The number of elements contained in the matched element set 23 size: function() { 24 return this.length; 25 }, 26 ....... 27 }; 28 // 将 jQuery.fn.init.prototype 指向 jQuery.fn ,这一步至关重要 29 jQuery.fn.init.prototype = jQuery.fn;
六 jQuery 中 $ 别名与其它库引发冲突解决
在 jQuery 源码,可发现做者为了便于用户使用,将 jQuery 以 window.jQuery 方式引入,同时,又为 jQuery 另起别名 $,所以,用户在代码不只可使用 jQuery,更可使用简便的 $ 。(jQuery.fn 为 jQuery.prototype 的别名)
而在众多的 javascript 类库,除了 jQuery ,另也有其它库,使用 $ 为别名,好比 prototype,若是在一个页面,同时,引入了 jQuery.js、prototype.js 就会引发冲突问题,由于二者都使用 $ 为别名。
接下来看看 jQuery 源码中提供的解决办法。
// 首先,在 jQuery 源码起始部分定义变量 _jQuery、_$ 值,以保存先前 jQuery、$ 真实值 // 此时,可想象页面分别按顺序引入 prototype.js、jquery.js // 页面运行 prototype.js ,此时,$、jQuery 为 prototype 类库所持有 // 当运行 jQuery.js ,由于,在 jQuery.js 中,又从新赋值了 jQuery、$ 所以,先将前一个类库所持有的值进行保存。 _jQuery = window.jQuery, _$ = window.$, // 再看看,jQuery 自身扩展的静态方法 :noConflict // 其函数体,就是实现将先前保存前一个类库中的 _$、_jQuery 中从新归还原来库 jQuery.extend({ noConflict: function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; })
未完待续