源码链接:内附实例代码
jQuery使用许久了,但是有一些API的实现实在想不通。于是抽空看了jQuery源码,现在把学习过程中发现的一些彩蛋介绍给大家(⊙0⊙)。
下面将使用简化的代码来介绍,主要关注jQuery的实现思想~>_<~
1 //匿名立即执行函数 2 //1.防止污染全局空间 3 //2.选择性保护内部变量 4 (function(window, undefined){ 5 //第二参数undefined设置而不传的原因: 6 // 外部发生这种情况:var undefined = 10时,undefined会被篡改 7 // 设置第二参数而不传,则undefined就会被重置回原来值 8 9 function jQuery(sel){ 10 return new jQuery.prototype.init(sel); 11 } 12 13 jQuery.prototype = { 14 constructor: jQuery, 15 init: function(sel){ 16 if(typeof sel === ‘string‘){ 17 var that = this; 18 //jQuery内部使用的是Sizzle,这里使用querySelectorAll替代 19 var nodeList = document.querySelectorAll(sel); 20 Array.prototype.forEach.call(nodeList, function(val, i){ 21 that[i] = val; 22 }) 23 this.selector = sel; 24 this.length = nodeList.length; 25 } 26 } 27 } 28 29 jQuery.prototype.init.prototype = jQuery.prototype; 30 31 //对外暴露jQuery:将jQuery绑定在window上面 32 window.$ = jQuery; 33 })(window);
--------------------------
jQuery一开始使用匿名立即执行函数包裹其内部,并在第5行对外暴露;
所谓的匿名立即执行函数即这个函数是匿名的(没有名字)、定义完后立即调用的;
当我们在外部调用$("div")时,其实调用的就是内部的jQuery("div");
(function(window, undefined){ //内部变量 //对外暴露jQuery:将jQuery绑定在window上面 window.$ = jQuery; })(window); $("div")
--------------------------
好,接下来稍复杂点,下面的代码主要实现如图的互相引用:
以$(‘div‘)调用为例:
从第2行代码可以看出,jQuery使用jQuery.prototype.init来实例化jQuery对象,但这会带来一个问题:
实例化的对象只能访问到init下的变量,而不能访问到jQuery.prototype(jQuery对外提供的API绑定在该对象下)。
于是乎,补写第21行代码,将init.prototype指向jQuery.prototype即可。
这样就完成了,使用init来实例化,且可以在init作用域下访问到jQuery.prototype。
1 function jQuery(sel){ 2 return new jQuery.prototype.init(sel); 3 } 4 5 jQuery.prototype = { 6 constructor: jQuery, 7 init: function(sel){ 8 if(typeof sel === ‘string‘){ 9 var that = this; 10 //jQuery内部使用的是Sizzle,这里使用querySelectorAll替代 11 var nodeList = document.querySelectorAll(sel); 12 Array.prototype.forEach.call(nodeList, function(val, i){ 13 that[i] = val; 14 }) 15 this.selector = sel; 16 this.length = nodeList.length; 17 } 18 } 19 } 20 21 jQuery.prototype.init.prototype = jQuery.prototype;
为什么使用jQuery.prototype.init来实例化对象,而不直接使用jQuery函数呢?
假设使用jQuery函数来实例化对象,这样对象之间的引用的确可以简化为 jQuery-->jQuery.prototype。
但是调用会变得繁琐起来:new $(‘div‘),所以基于这个考虑(猜测(⊙0⊙)),在内部使用较为复杂的实现,来简化调用。
--------------------------
好,最后,再来看一下init的实现。同样也简化了代码,只实现了最常用的一种情况。
jQuery会把获取到的nodeList处理成数组(方便后续使用),并在其下挂载一些变量,如length,selector。
1 init: function(sel){ 2 if(typeof sel === ‘string‘){ 3 var that = this; 4 //jQuery内部使用的是Sizzle,这里使用querySelectorAll替代 5 var nodeList = document.querySelectorAll(sel); 6 Array.prototype.forEach.call(nodeList, function(val, i){ 7 that[i] = val; 8 }) 9 this.selector = sel; 10 this.length = nodeList.length; 11 } 12 }
--------------------------
下一期预告:jQuery的XX如何实现?——2.show与链式调用
ps:代码已经上传到github中了