您的位置:首页 > Web前端 > JQuery

jQuery的XX如何实现?——3.data与cache机制

2016-05-11 20:17 295 查看
往期回顾:

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

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

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

源码链接:内附实例代码

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

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

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

(function(window, undefined) {

function jQuery(sel) {
return new jQuery.prototype.init(sel);
}

jQuery.prototype = {
constructor: jQuery,
init: function(sel) {
if(typeof sel === 'string'){
var that = this;
var nodeList = document.querySelectorAll(sel);
Array.prototype.forEach.call(nodeList, function(val, i){
that[i] = val;
})
this.selector = sel;
this.length = nodeList.length;
}
}
}

jQuery.prototype.init.prototype = jQuery.prototype;

window.$ = jQuery;

function Data() {
this.uid = 1;
//原来是防篡改对象(简化一下)
this.cache = {};
this.expando = 'jQuery' + Math.random();
}

Data.prototype = {
//获取elem的uid值
key: function(elem) {

var uid = elem[this.expando];
if(!uid) {
//为elem分配一个uid
uid = this.uid++;
elem[this.expando] = uid;
}

if(!this.cache[uid]) {
this.cache[uid] = {};
}

return uid;
},
set: function(elem, name, val) {
var cache = this.cache[this.key(elem)];
cache[name] = val;
},
get: function(elem, name) {
var cache = this.cache[this.key(elem)];
return cache[name];
}
}

var data_user = new Data();

jQuery.prototype.data = function(name, val) {
if(val) {
Array.prototype.forEach.call(this, function(elem) {
data_user.set(elem, name, val);
})
return this;
}
else return data_user.get(this[0], name);
}

})(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;

key: function(elem) {

var uid = elem[this.expando];
if(!uid) {
//为elem分配一个uid
uid = this.uid++;
elem[this.expando] = uid;
}

if(!this.cache[uid]) {
this.cache[uid] = {};
}

return uid;
}


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

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


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

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


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

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

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

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


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

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

var data_user = new Data();

jQuery.prototype.data = function(name, val) {
if(val) {
Array.prototype.forEach.call(this, function(elem) {
data_user.set(elem, name, val);
})
return this;
}
else return data_user.get(this[0], name);
}


最后,运行如代码:

$('#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上的数据;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: