深入理解jQuery.data() 的实现方式

jQuery.data() 的作用是为普通对象或 DOM Element 附加(及获取)数据。

下面将分三个部分分析其实现方式: 

1. 用name和value为对象附加数据;即传入三个参数,第一个参数为需要附加数据的对象,第二个参数为数据的名称,第三个参数为数据的值。当然,只是获取值的话,也可以不传入第三个参数。

2. 用另一个对象为对象附加数据;即传入两个参数,第一个参数为需要附加的数据对象(我们称之为“obj”),第二个参数也是一个对象(我们称之为“another”);“another”中包含的键值对将会被复制到 “obj” 的数据缓存(我们称之为“cache”)中。

3. 为 DOM Element 附加数据;DOM Element 也是一种 Object ,但 IE6、IE7 对直接附加在 DOM Element 上的对象的垃圾回收存在问题;因此我们将这些数据存放在全局缓存(我们称之为“globalCache”)中,即 “globalCache” 包含了多个 DOM Element 的 “cache”,并在 DOM Element 上添加一个属性,存放 “cache” 对应的 uid 。

用name和value为对象附加数据

使用 jQuery.data() 为普通对象附加数据时,其本质是将一个 “cache” 附加到了对象上,并使用了一个特殊的属性名称。

存放数据的 “cache” 也是一个 object,我们为 “obj” 附加的数据实际上成为了 “cache” 的属性。而 “cache” 又是 “obj” 的一个属性,在 jQuery 1.6中,这个属性的名称是 “jQuery16”加上一个随机数(如下面提到的 “jQuery16018518865841457738” )。

我们可以用下面的代码来测试 jQuery.data() 的功能:

<script type="text/javascript" src="jqueryjs"></script>
<script>
obj = {};
$data(obj, 'name', 'value');
documentwrite("$data(obj, 'name') = " + $data(obj, 'name') + '<br />'); 

for (var key in obj) {
 documentwrite("obj" + key + 'name = ' + obj[key]name);
}
</script> 

显示结果为:

$.data(obj, 'name') = value
obj.jQuery16018518865841457738.name = value 

在这段代码中,我们首先在 “obj” 上附加了一个属性(名称为“name”,值为“value”),然后通过 $.data(obj, 'name') 来获取所附加的数据。为了深入了解其中的实现机制,我们有使用了一个循环来获取 “obj” 的属性,实际上是取出了在 “obj” 上附加的 “cache”对象。

可以看到,jQuery.data() 实际上为 “obj” 附加到了名为 “jQuery16018518865841457738” (这个名称是随机的)的对象,也就是 “cache” 上。用 jquery.data() 方式为对象附加的属性实际上成为了这个 “cache” 的属性。

我们可以用下面的代码实现类似的功能:

$ = function() {
 var expando = "jQuery" + ("6" + Mathrandom())replace(/\D/g, ''); 

 function getData(cache, name) {
 return cache[name];
 } 

 function setData(cache, name, value) {
 cache[name] = value;
 } 

 function getCache(obj) {
 obj[expando] = obj[expando] || {};
 return obj[expando];
 } 

 return {
 data : function(obj, name, value) {
  var cache = getCache(obj); 

  if (value === undefined) {
  return getData(cache, name);
  } else {
  setData(cache, name, value);
  }
 }
 }
}();

function 中的第一行代码定义了 “expando” ,即 "jQuery1.6" 加上一个随机数(0.xxxx),并将其中非数字的部分去掉;这种格式将在jQuery的其他地方用到,这里不做探讨;只需要知道这是一个特殊的名称,并且可以用于标识不同的页面(比如不同 iframe 中的 “expando” 就会有所不同)。

接下来定义了获取数据的函数 getData(), 即从 “cache” 中获取一个属性;实际上也就是返回 cache[name] 。

然后是 setData() 函数,用于设置 “cache” 的属性;实际上也就是设置 cache[name] 的值。

之后是 getCache() , 获取 “obj” 上的 “cache”,即 obj[expando];如果 obj[expando] 为空,则进行初始化。

最后公开了 data 方法,先根据传入的 “obj”,获取附加在 “obj” 上的 “cache”; 当传入两个参数时,调用 getData()方法;当传入三个参数时,则调用 setData() 方法。

用另一个对象为对象附加数据

除了以提供 name 和 value 的方式进行赋值,我们还可以直接传入另一个对象( “another” )作为参数。这种情况下,“another” 的属性名称和属性值将被视为多个键值对,从中提取的 “name” 和 “value” 都会被复制到目标对象的缓存中。

功能测试代码如下:

<script type="text/javascript" src="jqueryjs"></script>
<script>
obj = {};
$data(obj, {name1: 'value1', name2: 'value2'}); 

documentwrite("$data(obj, 'name1') = " + $data(obj, 'name1') + '<br />' );
documentwrite("$data(obj, 'name2') = " + $data(obj, 'name2') + '<br />'); 

for (var key in obj) {
 documentwrite("obj" + key + 'name1 = ' + obj[key]name1 + '<br />');
 documentwrite("obj" + key + 'name2 = ' + obj[key]name2);
}
</script>

显示结果如下:

$.data(obj, 'name1') = value1
$.data(obj, 'name2') = value2
obj.jQuery1600233050178663064.name1 = value1
obj.jQuery1600233050178663064.name2 = value2 

上面的测试代码中,我们先将一个带有两个键值对的 “another” 对象传入,然后分别用 $.data(obj, 'name1') 和 $.data(obj, 'name2') 获取附加的数据;同样,为了深入了解其中的机制,我们通过遍历 “obj” 的方式取出了隐藏的 “cache” 对象,并获得了 “cache” 对象的 “name1” 属性和 “name2” 属性的值。

可以看到,jQuery.data() 实际上为 “obj” 附加了名为 “obj.jQuery1600233050178663064” 的对象,也就是 “cache” 上。用 jquery.data() 方式传入的键值对都被复制到了 “cache” 中。

我们可以用下面的代码实现类似的功能:

$ = function() {
 // Other codes 

 function setDataWithObject(cache, another) {
 for (var name in another) {
  cache[name] = another[name];
 }
 } 

 // Other codes 

 return {
 data : function(obj, name, value) {
  var cache = getCache(obj); 

  if (name instanceof Object) {
  setDataWithObject(cache, name)
  } else if (value === undefined) {
  return getData(cache, name);
  } else {
  setData(cache, name, value);
  }
 }
 }
}(); 

这段代码是在之前的代码的基础上进行修改的。首先增加了内部函数 setDataWithObject() ,这个函数的实现是遍历 “another” 的属性,并复制到 “cache” 中。

然后,在对外开放的 data 函数中,先判断传入的第二个参数的名称,如果这个参数是一个 Object 类型的实例,则调用 setDataWithObject() 方法。

为 DOM Element 附加数据

由于 DOM Element 也是一种 Object,因此之前的方式也可以为 DOM Element 赋值;但考虑到 IE6、IE7 中垃圾回收的问题(不能有效回收 DOM Element 上附加的对象引用),jQuery采用了与普通对象有所不同的方式附加数据。

测试代码如下:

<script type="text/javascript" src="datajs"></script>
<script>
windowonload = function() {
 div = documentgetElementById('div_test');
 $data(div, 'name', 'value');
 documentwrite($data(div, 'name'));
}
</script> 

显示结果如下:

value 

测试代码中,首先通过 document.getElementById 方法获取了一个 DOM Element (当然,也可以用 jQuery 的选择器),然后在这个 DOM Element 上附加了一个属性,随后就从 DOM Element 上取出了附加的属性并输出。

因为考虑到 IE6、IE7 对 DOM Element 上的对象引用的垃圾回收存在问题,我们不会直接在 DOM Element 上附加对象;而是使用全局cache,并在 DOM Element 上附加一个 uid。

实现方式如下:

$ = function() {
 var expando = "jQuery" + ("6" + Mathrandom())replace(/\D/g, '');
 var globalCache = {};
 var uuid = 0; 

 // Other codes 

 function getCache(obj) {
 if (objnodeType) {
  var id = obj[expando] = obj[expando] || ++uuid;
  globalCache[id] = globalCache[id] || {};
  return globalCache[id];
 } else {
  obj[expando] = obj[expando] || {};
  return obj[expando];
 }
 } 

 // Other codes
}(); 

这段代码与之前的代码相比,增加了 globalCache 和 uuid,并修改了 getCache() 方法。

globalCache 对象用于存放附加到 DOM Element 上的 “cache”,可以视为 “cache” 的“容器”。uuid 表示 “cache” 对应的唯一标识,是唯一且自增长的。uuid 或被存放在 DOM Element 的 “expando” 属性中。

getCache() 函数中增加了一个判断,即 “obj” 具有 “nodeType” 属性,就认为这是一个 DOM Element;这种情况下,就先取出附加在 “obj” 上的 id ,即 obj[expando] ;如果 obj[expando] 未定义,则先用 ++uuid 对其进行初始化;取出 id 之后,就到 globalCache 中找到对应的 “cache” ,即 globalCache[id], 并返回。

到此为止,jQuery.data() 函数的实现就介绍完了;但是,这里还有一个需要思考的问题:为什不都统一用 “globalCache” 存储,而要将 “cache” 直接附加到普通对象上?我认为这应该是一种性能优化的方式,毕竟少一个引用的层次,存取速度应该会略快一些。 jQuery 中这刻意优化的地方非常多,在许多原本可以统一处理的对方都进行了特殊处理。但这在一定程度上,也造成了阅读源码的障碍。当然这是作者(及其他代码贡献者)本身的编程哲学,这里就不加评论了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 深入学习jQuery中的data()

    data有什么作用? 在我们平时js编码过程中,我们经常会向DOM元素中添加各种自定义属性,这样有一个弊端. 1.假设我们在DOM元素中添加了一个属性,这个属性指向了某个js对象. dom1.ele = jsObj 2.当这个js对象发挥完作用后,我们已经用不到他了.这时候按理说应该把这个js变量清空,释放内存.大家都知道,如果一个js对象不存在任何外在引用的话,解释器会自动将其在内存中删除,这也是javascript相对于c++等手动管理内存的程序的优点. 3.但是这时候问题来了,因为DOM元

  • jQuery $.data()方法使用注意细节

    前段时间同事在群里对jQuery里的.data()方法大发牢骚: XXX(NNNNNNN) 15:11:34 <a id="a" data-xxx="00123" /> alert($('#a').data('xxx'));//123 data方法不靠谱 XXX(NNNNNNN) 15:13:17 老老实实用attr('data-xxx')吧细研究了下jQuery文档对.data()方法的描述: 复制代码 代码如下: As of jQuery 1.4.3

  • 详谈$.data()的用法和作用

    jQuery.data 即$.data().向元素附加数据,然后取回该数据 这是提供给客户端程序员使用的方法,它同时是setter/getter. 传一个参数,返回附加在指定元素的所有数据,即thisCachejQuery.data(el); // thisCache 传二个参数,返回指定的属性值jQuery.data(el, 'name'); 传三个参数,设置属性及属性值jQuery.data(el, 'name', 'jack');jQuery.data(el, 'uu', {}); 传四个

  • 深入理解jQuery.data() 的实现方式

    jQuery.data() 的作用是为普通对象或 DOM Element 附加(及获取)数据. 下面将分三个部分分析其实现方式:  1. 用name和value为对象附加数据:即传入三个参数,第一个参数为需要附加数据的对象,第二个参数为数据的名称,第三个参数为数据的值.当然,只是获取值的话,也可以不传入第三个参数. 2. 用另一个对象为对象附加数据:即传入两个参数,第一个参数为需要附加的数据对象(我们称之为"obj"),第二个参数也是一个对象(我们称之为"another&qu

  • 逐一介绍Jquery data()、Jquery stop()、jquery delay()函数(详)

    首先给大家介绍jquery data()函数 jQuery中data()函数用于向被选元素附加数据,或者从被选元素获取数据.通过data()函数存取的数据都是临时数据,一旦页面刷新,之前存放的数据都将不复存在. 一.jquery data()的作用 data() 方法向被选元素附加数据,或者从被选元素获取数据. 通过data()函数存取的数据都是临时数据,一旦页面刷新,之前存放的数据都将不复存在. 该函数属于jQuery对象(实例).如果需要移除通过data()函数存放的数据,请使用 remov

  • bootstrap data与jquery .data

    jquery官网对.data函数描述是:在匹配元素上存储任意相关数据 或 返回匹配的元素集合中的第一个元素的给定名称的数据存储的值. 存储键值(key/value): $("body").data("foo", 52); $("body").data("bar", { myType: "test", count: 40 }); $("body").data({ baz: [ 1, 2,

  • 深入理解jQuery事件绑定

    html: <a href="#" onclick="addBtn()">addBtn</a> <div id="mDiv"> <button class="cBtn" onclick="alert(11111)">button1</button> <button class="cBtn">button2</b

  • jQuery 常见操作实现方式和常用函数方法总结

    jQuery 常见操作实现方式 $("标签名") //取html元素 document.getElementsByTagName("") $("#ID") //取单个控件document.getElementById("") $("div #ID") //取某个控件中 控件 $("#ID #ID") // 通过控件ID取其中的控件 $("标签.class样式名") /

  • 深入理解jquery自定义动画animate()

    在以前很长一段时间里,网页上的各种特效还需要采用flash 在进行.但最近几年里,我们已经很少看到这种情况了,绝大部分已经使用JavaScript 动画效果来取代flash.这里 说的取代是网页特效部分,而不是动画.网页特效比如:渐变菜单.渐进显示.图片轮播等:而动画比如:故事情节广告.MV 等等. 如果复制当前代码进行在本地测试的时候,请注意把不需要(其他功能展示)的代码注释掉. <!DOCTYPE html> <html xmlns="http://www.w3.org/1

  • 深入理解jQuery中的事件冒泡

    1.什么是冒泡 eg: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>事件冒泡</title> <script src="

  • 深入理解jQuery 事件处理

    浏览器的事件模型 DOM第0级事件模型 1.Event实例 他的属性提供了关于当前正被处理的已触发事件的大量信息.这包括一些细节,比如在哪个元素上触发的事件.鼠标事件的坐标以及键盘事件中单击了哪个键. 2.事件冒泡 当触发 dom 树中一个元素上的事件时,事件模型会检查这个元素是否已经创建了特定的事件处理器.如果是,就会调用已创建的事件处理器.然后,事件模型会检查目标元素的父元素,看其是否已经为此事件类型创建了处理器.如果是,就调用已创建的处理器,之后检查它的父元素,以及父元素的父元素,以此类推

  • 深入理解JQuery循环绑定事件

    深入理解JQuery循环绑定事件 <html> <head> <title></title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> </head> <body> <script typ

  • 深入理解jquery跨域请求方法

    项目中关于ajax jsonp的使用, 出现了问题:可以成功获得请求结果,但没有执行success方法 总算搞定了,记录一下 function TestAjax() { $.ajax({ type : "get", async : false, url : "ajaxHandler.ashx", //实际上访问时产生的地址为: ajax.ashx?callbackfun=jsonpCallback&id=10 data : {id : 10}, cache

随机推荐