`
裴小星
  • 浏览: 265832 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
8ccf5db2-0d60-335f-a337-3c30d2feabdb
Java NIO翻译
浏览量:27853
F3e939f0-dc16-3d6e-8c0b-3315c810fb91
PureJS开发过程详解
浏览量:74380
07a6d496-dc19-3c71-92cf-92edb5203cef
MongoDB Java ...
浏览量:63081
社区版块
存档分类
最新评论

jQuery.data() 的实现方式

阅读更多
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="jquery.js"></script>
<script>
obj = {};
$.data(obj, 'name', 'value');
document.write("$.data(obj, 'name') = " + $.data(obj, 'name') + '<br />');

for (var key in obj) {
	document.write("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" + ("1.6" + Math.random()).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="jquery.js"></script>
<script>
obj = {};
$.data(obj, {name1: 'value1', name2: 'value2'});

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

for (var key in obj) {
	document.write("obj." + key + '.name1 = ' + obj[key].name1 + '<br />');
	document.write("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采用了与普通对象有所不同的方式附加数据。

    测试代码如下:

<div id="div_test" />

<script type="text/javascript" src="data.js"></script>
<script>
window.onload = function() {
	div = document.getElementById('div_test');
	$.data(div, 'name', 'value');
	document.write($.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" + ("1.6" + Math.random()).replace(/\D/g, '');
    var globalCache = {};
    var uuid = 0;

    // Other codes ...

    function getCache(obj) {
        if (obj.nodeType) {
            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 中这刻意优化的地方非常多,在许多原本可以统一处理的对方都进行了特殊处理。但这在一定程度上,也造成了阅读源码的障碍。当然这是作者(及其他代码贡献者)本身的编程哲学,这里就不加评论了。
18
12
分享到:
评论
5 楼 focus2008 2013-12-10  
文章很深入!博主很强大!

问个问题,在Ajax应用中,是否可以使用 .data方法来代替隐藏
input 来存放数据,之后获取之前隐藏的数据,进行ajax提交呢?

比如我现在都是这样用:

一个 ajax 调用 返回 一些数据,然后我将需要的数据保存在 input 中,隐藏起来,然后下一个提交时,获取这些隐藏input中的数据,然后异步提交。说明一下,我做的系统是典型的 单页面 系统(web game)。那么有了 .data方法,我是不是可以随便在一个 div中使用 .data方法存放数据,然后提交时,用.data取得数据,然后异步提交呢??请指点。
4 楼 bj_ling 2012-12-25  
我在IE6上就不能使用data()...请问如何解决呢。
3 楼 warner 2012-08-18  
document.write("obj." + key + '.name = ' + obj[key].name);
改为
document.write("obj." + key + '.name = ' + obj[key].data.name);
2 楼 裴小星 2011-05-24  
jquery 的注释有说明,

We have to handle DOM nodes and JS objects differently because IE6-7
can't GC object references properly across the DOM-JS boundary

IE6、IE7 中, 直接把 object 作为属性附加到 DOM Element 上,
那么这个 objet 占用的内存将不会被有效地回收。

所以 data() 函数的实现中只在 DOM Elemet 上存了一个 ID 。
1 楼 hastune 2011-05-23  
引用
因为考虑到 IE6、IE7 对 DOM Element 上的对象引用的垃圾回收存在问题


博主可以说说是什么问题吗

相关推荐

    jQuery.mmenu-jquery.mobile最好看的侧边菜单

    5. **交互集成**:利用jQuery Mobile的触控事件(如`tap`和`swipe`)与jQuery.mmenu的API相结合,实现更丰富的用户交互。 **示例代码** ```html &lt;!DOCTYPE html&gt; &lt;link rel="stylesheet" href="jquery.mobile...

    Jquery.json.js

    **jQuery与JSON简介** jQuery是一个高效、简洁且易用的JavaScript库,它极大地简化了JavaScript编程,使得DOM操作、...同时,理解jQuery与JSON的交互方式对于Web开发人员来说至关重要,能够提升开发效率和代码质量。

    jquery.paginate.js

    1. 简单易用:jQuery.paginate.js的核心优势在于其简洁的API接口,开发者只需几行代码就能实现分页功能。通过调用特定的jQuery方法,可以快速将分页组件添加到页面上。 2. 自定义样式:该插件允许开发者自定义分页...

    利用jquery.carousel.js实现自动轮播旋转木马效果(带前后按钮和小按钮5个)

    可以将jQuery库和`jquery.carousel.js`通过CDN链接或本地文件的方式引入到HTML文档的`&lt;head&gt;`部分: ```html &lt;script src="https://code.jquery.com/jquery-3.x.y.min.js"&gt;&lt;/script&gt; &lt;script src="path/to/jquery....

    jquery.PrintArea.js-2.4.0-打印功能.rar

    jQuery PrintArea.js插件是一个优秀的解决方案,它允许开发者轻松地实现这一需求。本文将深入探讨jQuery PrintArea.js 2.4.0版本的核心特性和使用方法。 一、jQuery PrintArea.js概述 jQuery PrintArea.js是一款轻...

    jquery.kxbdmarquee插件

    在这个库的基础上,开发者创建了许多插件来扩展其功能,其中`jquery.kxbdmarquee`就是一款实现无缝滚动效果的插件。无缝滚动是一种常见的网页元素动态展示方式,它能让内容在页面上不间断地滚动,为用户带来流畅的...

    jquery.marquee.js官方下载

    jQuery Marquee是基于流行的JavaScript库jQuery的一款插件,它提供了一种简单的方式来实现元素的自动滚动效果,支持自定义速度、方向、暂停和恢复等操作。其主要目标是为开发者提供一个易于使用且功能丰富的解决方案...

    基于jQuery.i18n.properties插件实现前端页面国际化demo

    jQuery.i18n.properties插件是实现这一目标的一个强大工具,尤其适合那些基于jQuery构建的项目。这个插件提供了一种简单的方法来管理并加载不同语言版本的属性文件,使得前端开发者可以轻松地实现在不同地区使用的多...

    jquery.pagination.js实现分页的三种形式,实例

    jQuery pagination.js 是一个轻量级的插件,专门用于实现这种功能。在这个实例中,我们将探讨如何使用 `jquery.pagination.js` 实现三种不同的分页形式:基本分页、AJAX 无刷新分页以及自定义分页属性。 **基本分页...

    jquery.lazyload.js

    5. **易于集成和定制**:作为基于jQuery的插件,jQuery.Lazyload.js拥有丰富的API和配置选项,开发者可以根据需求进行定制,实现不同的加载效果,如预加载、动画效果等。 在实际应用中,jQuery.Lazyload.js的使用...

    jquery.onoff

    然后,你可以通过以下方式引入jQuery.onoff插件: ```html &lt;script src="path/to/jquery.js"&gt; &lt;script src="path/to/jquery.onoff.min.js"&gt; ``` 三、基本使用方法 在HTML中创建一个简单的开关按钮: ```html ``...

    jquery.table2excel.js.zip

    jQuery.table2excel.js是一款轻量级的jQuery插件,它实现了这一功能,允许用户将网页中的HTML表格便捷地导出为Excel文件。 ### jQuery.table2excel.js的工作原理 该插件的核心是利用浏览器的Blob对象和Data URL...

    jquery.orgchart.js

    4. **多方向布局**:除了传统的自上而下的布局,还支持自下而上、自左向右、自右向左等多种布局方式,适应不同场景。 5. **动态加载**:对于大型组织结构,可以实现分层加载,只在需要时加载子节点,减少初始加载...

    jQuery.mobile-1.0.1.js与jQuery.mobile-1.0.1.min.js

    1. **页面结构**:jQuery Mobile采用单一页面架构,通过AJAX技术实现页面无刷新切换,提升了用户体验。 2. **数据链接(data-url)**:通过添加"data-url"属性,可以为每个页面设置独特的URL,便于书签和历史记录...

    jquery.common通用方法

    3. 数据操作:为了方便数据的存储和读取,jQuery.common可能提供了一种统一的方式来操作元素的data属性,甚至可以扩展到JSON格式的数据操作。 4. 动画效果:jQuery库本身就具有强大的动画功能,jQuery.common则可能...

    jquery.localize.zip

    jQuery.Localize 是一个优秀的 JavaScript 插件,专为实现这一目标而设计。该插件简化了在网页中进行本地化处理的过程,尤其在Java开发的项目中,它能与后端服务完美结合,提供高效且灵活的国际化解决方案。 一、...

    表格排序插件jquery.tableSort.js

    jquery.tableSort.js不仅限于基本的表格排序,还可以结合其他jQuery插件,如DataTables,实现更强大的表格功能,如分页、过滤和搜索等。同时,它也可以与其他前端框架如AngularJS、Vue.js等配合使用,实现动态数据的...

    JQuery.param

    在提供的压缩包中,文件`jquery.params.js`可能是一个定制版本的jQuery.param实现,或者包含了一些扩展功能。在实际项目中,如果你遇到对原版jQuery的功能有特殊需求的情况,可以考虑使用这个文件来替换或补充原有的...

    jQuery.easyui.1.2.6 Demo

    在1.2.6版本的Demo中,我们可以看到这些组件的实际运行效果和配置方式。例如,数据网格允许开发者轻松地展示和操作大量数据,通过设置列宽、排序、过滤等功能,提高用户体验。 其次,jQuery.easyui 强调的是“易用...

Global site tag (gtag.js) - Google Analytics