(令: jquery从2.0之后就不兼容IE 6/7/8 了)
;(function(global, factory) { // 传入window可以将其作为一个局部变量使用,缩短了作用域链,大大加快执行速度 factory(global); }(typeof window !== "undefined" ? window : this, function(window, noGlobal) { // jquery方法 var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context ); }; // jQuery.fn 是 jquery对象的原型对象 jQuery.fn = jQuery.prototype = {}; // 核心方法 // 回调系统 // 异步队列 // 数据缓存 // 队列操作 // 选择器引 // 属性操作 // 节点遍历 // 文档处理 // 样式操作 // 属性操作 // 事件体系 // AJAX交互 // 动画引擎 if ( typeof noGlobal === strundefined ) { window.jQuery = window.$ = jQuery; } return jQuery; }));
关于上述代码,解释如下:
jQuery的整体代码包裹在一个立即执行的自调用匿名的函数中,这样可以尽量减少和其他第三方库的干扰;自动初始化这个函数,让其只构建一次。
在上述代码最后,将jQuery对象添加到全局window上,并为之设置变量$,从而使得可以在外界访问jQuery;
为自调用匿名函数设置参数global,并传入参数window,这样一方面可以缩短作用域链,可以尽快访问到window;
自调用函数的原理(立即执行的自调用函数)
function
对象了。同时小括号也取得了这个函数的引用位置,然后传入参数就可以直接执行了。总结: 全局变量是魔鬼, 匿名函数可以有效的保证在页面上写入JavaScript,而不会造成全局变量的污染,通过小括号,让其加载的时候立即初始化,这样就形成了一个单例模式的效果从而只会执行一次。(function( global, factory ) { // 因为jquery既要再普通环境下运行,也要再例如AMD、commonJs下运行,所以我们需要做不同的适应 // node CommonJs规范 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 { // AMD factory( global ); } // 传入参数(window和一个执行函数) }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { // 【1】 // 创建jQuery对象, 实际上是jQuery.fn.init所返回的对象 var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context ); // 如果调用new jQuery, 生成的jQuery会被丢弃,最后返回jQuery.fn.init对象 // 因此可以直接调用jQuery(selector, context), 不需要使用new // 如果使用new jQuery()容易出现死循环 // 我们平常使用 $() ,就是直接调用jquery函数了 } // 【2】 // 创建jQuery对象原型,为jQuery添加各种方法 jQuery.fn = jQuery.prototype = { ... } // 【3】 // 在调用new jQuery.fn.init后, jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype // 相当于将所有jQuery.fn的方法都挂载到一开始jQuery函数返回的对象上 // 这里就是jquery的一个独特之处了,非常的巧妙 jQuery.fn.init.prototype = jQuery.fn; // 【4】 // 创建jQuery.extend方法 jQuery.extend = jQuery.fn.extend = function() {、 ... } // 【5】 // 使用jQuery.extend扩展静态方法 jQuery.extend({}); // 【6】 // 为window全局变量添加$对象,在给window全局添加变量的时候很有可可能会导致变量命名冲突哦,我们之后会学习到如何处理这种命名冲突的解决方法 if ( typeof noGlobal === strundefined ) { // var strundefined = typeof undefined window.jQuery = window.$ = jQuery; // $('') // 同 jQuery('') } return jQuery; }));
可以这么理解,jquery主要的任务就是获取DOM
。操作DOM
。
jQuery
的入口都是通过$()
来的,通过传入不同的参数,实现了9种重载方法。
1. jQuery([selector,[context]]) 2. jQuery(element) 3. jQuery(elementArray) 4. jQuery(object) 5. jQuery(jQuery object) 6. jQuery(html,[ownerDocument]) 7. jQuery(html,[attributes]) 8. jQuery() 9. jQuery(callback) // 9种用法整体来说可以分三大块:选择器、dom的处理、dom加载。
在jquery内部使用了一种类数组对象的形式,这也是为什么我们获取到同一个class的许多DOM后,既能够调用jquery的方法,又能通过数组的方式来处理每一个dom对象了(比如遍历)。
例子喽
通过$(".Class")构建的对象结构如下所示:\
<p> <span class="span">1</span> <span class="span">2</span> <span class="span">3</span> </p> console.log($('.span')); // jQuery.fn.init(3) [span.span, span.span, span.span, prevObject: jQuery.fn.init(1), context: document, selector: ".span"] // 0:span.span // 1:span.span // 2:span.span // context: document // length: 3 // prevObject: jQuery.fn.init [document, context: document] // selector:".span" // __proto__:Object(0)
// 模拟一下 function Ajquery(selecter) { // 如果传入的不是一个对象,则将其转换为对象 if(!(selecter instanceof Ajquery)) { return new Ajquery(selecter); } var elem = document.getElementById(/[^#].*/.exec(selector)[0]); // 获取id this[0] = elem; this.length = 1; this.context = document; this.selector = selector; this.get = function(num) { return this[num]; } return this; } // 使用 $('#show2').append(Ajquery('#book').get(0)); // 因此 $('')获取到的就是一个类数组对象
jQuery的无new构造原理
我们在构造jQuery对象的时候,并没有使用new来创建,但其实是在jQuery
方法的内部,我们使用了new
,这样就保证了当前对象内部就又了一个this对象,并且吧所有的属性和方法的键值对都映射到this上了,所以既可以通过链式取值,也可以通过索引取值。jquery除了实现了类数组结构
, 方法的原型共享
,还实现了静态和实例的共享
.
javascript就是函数式语言
,函数可以实现类,所以javascript不是一个严格的面向对象的语言。
平时的情况
function ajquery(name){ this.name = name; } ajquery.prototype = function(){ say: function(){ return this.name; } } var a = new ajquery(); a.say();
但是在jquery中却不是这么来的。jQuery没有使用new运行符将jQuery显示的实例化,还是直接调用其函数
$().ready() $().noConflict()
如果要实现不用new直接获得实例
var aQuery = function(selector, context) { return new aQuery(); // 直接new一下 } aQuery.prototype = { name:function(){}, age:function(){} } // 如果是上诉的样子,直接new aQuery()则会导致死循环。
如何得到一个正确的实例呢,那么可以把jQuery类当作一个工厂方法来创建实例,把这个方法放到jQuery.prototye原型中,然后实例化这个方法,从而创建一个实例
// 下面就是jquery的写法了 jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context, rootjQuery ); }, // 但是问题又来了,init中的this指向的是实例init的原型,就导师了jquery类的this分离了, // 解决这个问题的方法是: jQuery.fn.init.prototype = jQuery.fn;