一.引子
大家想想,在未使用jQuery或者其他js框架前,只用原生js的时候,怎么存储数据的呢?在刚结束js的时候,我是将每个跟节点有关的属性都使用setAttribute(name,value)保存在节点上。下次取就可以直接getAttribute(name),一个节点使用这种方式保存很多数据,效率肯定不高的。在有时候要对节点保存大量的数据的时候,还有没更好的办法来存储数据呢?下面来看看jQuery是如何做的。
二.原理
jQuery数据的存储原理是:
1)定义了一个对象$.cache 保存所有数据
2)对每一个存储数据的DOM节点都对应一个数字index,这个DOM节点下的所有值都存储在$.cache(index)对象中(这么看是不是觉得$.cache是一个数组? 其实js中数组和对象很像,数组也是对象,对象就是一组属性的集合)。
3)对每一个存储数据的DOM节点都生成一个唯一的index。这个index值保存在节点的expando属性中。
4)expando是什么?就是每一个jQuery框架加载的时候内部生成的一个随机序列。这个序列一个jQuery加载完只有唯一一个。
让图片来更清楚的描述:
调用$(“#test”).data(“name”)时会先找到对象属性jQuery17102199497243038011($.expando)的值(当前为1),这个值就1就是上面说的index。对象所有存储的值都是放在$.cache[“1”]对象中。
下面代码可验证:
$("#test").data("abc", "def");
var cacheIndex = document.getElementById("test")[$.expando]; //获取index
//$.expando在1.2版本里访问不到,不能
var obj = $.cache[cacheIndex];
alert(obj["abc"]); //def 注:这是jQuery1.6 前取值方式
//注: 在jquery1.7版本中对存储值有所改变。需要obj[“data”]["abc"]才能取到。也就是说$(“#test”).data(“abc”,”def”)不是存在上述obj对象中,而是存在obj[“data”]对象中(多了一层data对象,变得更深了)。
三.源码
下面来看代码是如何做到的:
jQuery.fn.extend({
//扩展jQuery的对象方法data
data: function( key, value ) {
var parts, attr, name,data = null;
//如果key没有,执行的操作
if ( typeof key === "undefined" ) {
if ( this.length ) {
/**获取对象数组第一个元素的数据缓存cache
* (该对象包含当前元素的所有存储的数据)
*/
data = jQuery.data( this[0] );
//元素节点
if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
attr = this[0].attributes;
for ( var i = 0, l = attr.length; i < l; i++ ) {
name = attr[i].name;
if ( name.indexOf( "data-" ) === 0 ) {
name = jQuery.camelCase( name.substring(5) );
dataAttr( this[0], name, data[ name ] );
}
}
jQuery._data( this[0], "parsedAttrs", true );
}
}
return data;
} else if ( typeof key === "object" ) {
return this.each(function() {
jQuery.data( this, key );
});
}
parts = key.split(".");
parts[1] = parts[1] ? "." + parts[1] : "";
//.data(name)格式,取值
if ( value === undefined ) {
data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
// Try to fetch any internally stored data first
if ( data === undefined && this.length ) {
data = jQuery.data( this[0], key );
data = dataAttr( this[0], key, data );
}
return data === undefined && parts[1] ?
this.data( parts[0] ) :
data;
//.data(name, value)格式,设置值
} else {
return this.each(function() {
var self = jQuery( this ),
args = [ parts[0], value ];
//触发事件,如果对节点设置值绑定了事件,在做操作时触发事件
self.triggerHandler( "setData" + parts[1] + "!", args );
jQuery.data( this, key, value );
self.triggerHandler( "changeData" + parts[1] + "!", args );
});
}
}
});
下面是静态方法:
jQuery.extend({
/** jQuery静态方法,算是data的核心了
* jQuery很多都是这种模式,在静态方法里定义一个核心的处理方法
* 在对象方法中定义用户操作的接口,就是API。
* 如事件:$("#id").click(),$("xx").hover()等等。
* 但最终处理都是调$("#id").on() 到最后是$.event.add()方法
*/
data: function( elem, name, data, pvt /* Internal Use Only */ ) {
//判断当前节点能不能存储数据
if ( !jQuery.acceptData( elem ) ) {
return;
}
var privateCache, thisCache, ret,
internalKey = jQuery.expando,
getByName = typeof name === "string",
/**判断元素是否是DOM对象,如果是DOM对象才使用全局cache,普通js对象,直接增加属性即可.
* DOM对象可以直接增加属性,为什么这个非得用全局对象呢?
* 这主要是解决IE6-7浏览器垃圾回收对于js创建的DOM对象的属性不能回收
* 验证方法:(使用sIEve 可看到有内存泄露)
* function A() {
* var a = document.createElement("div");
* a["b"] = function(){};
* document.getElementById("test").appendChild(a);
* a.parentNode.removeChild(a);
* }
* A();
*/
isNode = elem.nodeType,
cache = isNode ? jQuery.cache : elem,
//获取index
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
isEvents = name === "events";
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
return;
}
if ( !id ) {
//为每一个存储数据在全局cache中的DOM节点分配一个唯一index
if ( isNode ) {
elem[ internalKey ] = id = ++jQuery.uuid;
} else {
id = internalKey;
}
}
if ( !cache[ id ] ) {
cache[ id ] = {};
// Avoids exposing jQuery metadata on plain JS objects when the object
// is serialized using JSON.stringify
if ( !isNode ) {
cache[ id ].toJSON = jQuery.noop;
}
}
//如果name是对象或函数,继承里面所有方法.注意:这边为什么判断pvt ?
if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
cache[ id ] = jQuery.extend( cache[ id ], name );
} else {
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
}
}
privateCache = thisCache = cache[ id ];
//要知道pvt是jQuery自己内部使用的,将保存用户和jQuery内部数据的保存分开了。
//将我们设置的name/value值
//放在了cache[id].data对象中,而jQuery内部数据直接放在了cache[id]中
//好处不言而喻,将用户和jQuery框架的数据分开保存,避免了名称冲突
//1.7版本之后才区分开.上面例子已经说了
if ( !pvt ) {
if ( !thisCache.data ) {
thisCache.data = {};
}
thisCache = thisCache.data;
}
//存储数据
if ( data !== undefined ) {
thisCache[ jQuery.camelCase( name ) ] = data;
}
// Users should not attempt to inspect the internal events object using jQuery.data,
// it is undocumented and subject to change. But does anyone listen? No.
if ( isEvents && !thisCache[ name ] ) {
return privateCache.events;
}
if ( getByName ) {
ret = thisCache[ name ];
if ( ret == null ) {
ret = thisCache[ jQuery.camelCase( name ) ];
}
} else {
ret = thisCache;
}
return ret;
}
});
本章结束,有不对和不准确的地方望大家指正。有疑问欢迎留言。
- 大小: 33.3 KB
分享到:
相关推荐
《jQuery源码分析》 jQuery,作为一款广泛使用的JavaScript库,极大地简化了DOM操作、事件处理、动画制作以及Ajax交互。深入理解其源码对于提升JavaScript编程技能和优化前端性能至关重要。本文将从核心概念、设计...
### jQuery源码分析系列_1.6 #### 一、前言 在现代Web开发领域,jQuery无疑是一款具有里程碑意义的JavaScript库。它通过简洁、强大的API极大地简化了DOM操作、事件处理、Ajax交互以及动画等功能,使得前端开发变得...
《jQuery源码分析——魔术方法》 jQuery,作为一款广泛使用的JavaScript库,以其简洁的API和强大的功能赢得了开发者们的喜爱。在深入理解jQuery的工作原理时,我们常常会遇到一些“魔术方法”,这些方法在特定场景...
《jQuery 1.2.6 源码分析与API详解》 jQuery 是一个广泛使用的JavaScript库,它极大地简化了JavaScript编程,使得DOM操作、事件处理、动画制作以及Ajax交互变得更加便捷。本篇文章将深入剖析jQuery 1.2.6版本的源码...
**jQuery博客源码详解** jQuery,作为一款广泛使用的JavaScript库,极大地简化了DOM...通过分析和实践这些源码,你可以深入了解jQuery的工作原理,提升你的前端开发技能,并能更好地构建高效、互动性强的博客系统。
在本教程中,我们使用PHP作为服务器端编程语言,jQuery用于简化JavaScript的开发和进行异步HTTP请求(AJAX),MySQL作为数据库存储数据。整个流程可以概括为:前端通过jQuery发起AJAX请求,请求被发送至后端的PHP...
总的来说,这个实例源码是学习jQuery和EasyUI结合使用的一个良好起点,通过阅读和理解代码,你可以掌握如何使用这两种工具来构建数据驱动的Web应用,实现CRUD操作。同时,也能了解到常见的三层架构在Web开发中的应用...
**jQuery 1.3及其参考手册源码分析** jQuery是一个广泛使用的JavaScript库,极大地简化了JavaScript的DOM操作、事件处理、动画制作以及Ajax交互。在jQuery 1.3版本中,这一系列特性得到了进一步的优化和增强,为...
《锋利的jQuery源码》是一本专注于深入解析jQuery库的书籍,其第二版更是针对jQuery的最新版本进行了详尽的分析。这本书的核心是通过实际案例来帮助读者理解并掌握jQuery的内部工作原理,从而提升JavaScript开发技能...
《jQuery坦克大战源码解析与游戏开发技术探析》 jQuery坦克大战是一款基于JavaScript和jQuery库开发的在线游戏,它沿袭了经典FC游戏坦克大战的玩法,为玩家提供了丰富的娱乐体验。本篇文章将深入探讨该源码的技术...
2. 主题和帖子管理:C#处理数据存储和检索,Jquery实现动态加载和分页。 3. 评论和回复功能:C#处理用户互动,Jquery实现实时更新和通知。 4. 用户权限系统:C#实现角色和权限分配,Jquery可能用于前端权限展示和...
`each()`函数遍历集合,`extend()`处理对象扩展,`data()`管理元素的数据存储。 ### 8. 性能优化 jQuery 1.3版本已经考虑了性能优化,如缓存DOM查询结果、批量操作DOM、避免内存泄漏等策略。随着版本迭代,jQuery...
1. **选择器引擎Sizzle**:jQuery的核心之一是选择器引擎Sizzle,它实现了CSS1至CSS3的选择器,使我们能够用类似CSS的语法来选取DOM元素。例如,`$("#id")`选取ID为id的元素,`$(".class")`选取所有class为class的...
通过以上分析,我们可以看到jQuery未压缩版本源码的学习不仅涉及到了JavaScript的基础知识,还涵盖了DOM操作、字符串处理、浏览器兼容性等多个方面。这为我们深入理解和掌握jQuery的内部工作原理提供了宝贵的资料。
《jQuery源码分析-总体架构解析》 在深入探究jQuery的源码之前,我们首先要理解其总体架构的设计理念。jQuery以其高效、易用的特性深受开发者喜爱,而这背后离不开其精心设计的架构。本文将围绕jQuery的核心构造...
**jQuery: 深入理解与源码分析** jQuery 是一个广泛使用的 JavaScript 库,它极大地简化了 DOM 操作、事件处理、动画效果以及 AJAX 交互。jQuery 的流行在于其简洁的 API 和高效的代码实现,使得开发者能够用更少的...
"jQuery 源码分析笔记"探讨了jQuery的核心设计和实现,特别是其如何简化JavaScript开发,并且深入研究了jQuery的源码结构。 jQuery的创建方式是一个自执行的匿名函数,这样做的好处在于它不会污染全局命名空间,...
《jQuery源码解析与经典应用探析》 jQuery,作为一款强大的JavaScript库,自诞生以来就深受开发者喜爱,它的简洁语法、高效的DOM操作以及丰富的插件生态,使得网页动态效果的实现变得轻而易举。本文将深入探讨...
本文将深入探讨 jQuery 1.4 版本,包括其核心特性、API 使用以及源码分析。 1. **jQuery 的核心理念** - **选择器**: jQuery 提供了丰富的 CSS 选择器,使得选取 HTML 元素变得简单。例如,`$("#id")` 用于选取 ID...