jQuery的XX如何实现?——1.框架

源码链接:内附实例代码

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中了

原文地址:https://www.cnblogs.com/jiahuix/p/5475146.html