你的位置:首页 > Java教程

[Java教程]jQuery的XX如何实现?——3.data与cache机制


往期回顾:

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

jQuery的XX如何实现?——2.show与链式调用

--------------------------

源码链接:内附实例代码

jQuery使用许久了,但是有一些API的实现实在想不通。于是抽空看了jQuery源码,现在把学习过程中发现的一些彩蛋介绍给大家(⊙0⊙)。

下面将使用简化的代码来介绍,主要关注jQuery的实现思想~>_<~

相较于第一篇(与第二篇无相关性),代码更新了:27~71

 1 (function(window, undefined) { 2  3   function jQuery(sel) { 4     return new jQuery.prototype.init(sel); 5   } 6    7   jQuery.prototype = { 8     constructor: jQuery, 9     init: function(sel) {10       if(typeof sel === 'string'){11         var that = this;12         var nodeList = document.querySelectorAll(sel);13         Array.prototype.forEach.call(nodeList, function(val, i){14           that[i] = val;15         })16         this.selector = sel;17         this.length = nodeList.length;18       }19     }20   }21   22   jQuery.prototype.init.prototype = jQuery.prototype;23   24   window.$ = jQuery;25   26   27   function Data() {28     this.uid = 1;29     //原来是防篡改对象(简化一下)30     this.cache = {};31     this.expando = 'jQuery' + Math.random();32   }33   34   Data.prototype = {35     //获取elem的uid值36     key: function(elem) {37       38       var uid = elem[this.expando];39       if(!uid) {40         //为elem分配一个uid41         uid = this.uid++;42         elem[this.expando] = uid;43       }44       45       if(!this.cache[uid]) {46         this.cache[uid] = {};47       }48       49       return uid;50     },51     set: function(elem, name, val) {52       var cache = this.cache[this.key(elem)];53       cache[name] = val;54     },55     get: function(elem, name) {56       var cache = this.cache[this.key(elem)];57       return cache[name];58     }59   }60   61   var data_user = new Data();62   63   jQuery.prototype.data = function(name, val) {64     if(val) {65       Array.prototype.forEach.call(this, function(elem) {66         data_user.set(elem, name, val);67       })68       return this;69     }70     else return data_user.get(this[0], name);71   }72   73   74 })(window);

--------------------------

cache在jQuery中的作用:为dom分配一个存储空间。简而言之,就是为了保存数据(⊙0⊙),比如:

1.data API     2.事件队列

 下面结合图片与代码来介绍cache与dom之间是如何建立联系的。

在图中可以看到,elem下有一个{jQueryXXX : cache.uid}的键值对。通过elem[Data.expando]可以获取到这个elem在Data下的cache.uid。有了cache.uid后,我们就可以取到elem在Data.cache中的数据。

有点绕,我们用伪代码整理一下:

var uid = elem[Data.expando];var data = Data.cache[uid];

 

最后获取到的data就是elem在Data.cache中保存的数据╰( ̄▽ ̄)╮

 

--------------------------

好了,有了上面的思路,我们现在用js代码实现出来。

先介绍Data.prototype下的三个方法,有了这三个方法,后续的操作都会非常简便╰( ̄▽ ̄)╮

Data.prototype.key(获取elem的uid):

1.获取elem在Data.cache中的uid【38行】;

2.为新的elem在Data.cache中建立一个新的空间【39~47行】,并返回uid;

36 key: function(elem) {37       38   var uid = elem[this.expando];39   if(!uid) {40     //为elem分配一个uid41     uid = this.uid++;42     elem[this.expando] = uid;43   }44   45   if(!this.cache[uid]) {46     this.cache[uid] = {};47   }48   49   return uid;50 }

Data.prototype.set(保存数据):

51 set: function(elem, name, val) {52   var cache = this.cache[this.key(elem)];53   cache[name] = val;54 }

Data.prototype.get(读取数据):

55 get: function(elem, name) {56   var cache = this.cache[this.key(elem)];57   return cache[name];58 }

三个函数实现完毕后,其实针对cache的操作就非常简便了。保存数据就调用set,读取数据就调用get。

 

--------------------------

接下来,利用cache机制来实现data API

//保存数据$('#div').data('key1', 123);//读取数据$('#div').data('key1');

 

实现起来也非常简便,所以直接上代码,各位客官自己琢磨下了~>_<~+

代码的第66行就是保存数据,而第70行就是读取数据。

61 var data_user = new Data();62   63 jQuery.prototype.data = function(name, val) {64   if(val) {65     Array.prototype.forEach.call(this, function(elem) {66       data_user.set(elem, name, val);67     })68     return this;69   }70   else return data_user.get(this[0], name);71 }

 

最后,运行如代码:

$('#div').data("num", 123);$('#div').data("objVal", {val:123});console.log($('#div').data("num"));console.log($('#div').data("objVal"));

 

得到结果:

 

--------------------------

最后再唠叨几句:这里实现data API是非常简陋的~>_<~+。实际中:

1.jQuery会对data的name进行格式限制(比如data-*);

2.还能识别dom上的数据(比如<div data-haha="123"></div>);

3.elem被remove掉的时候,还会删除对应cache上的数据;