jQuery.data的是jQuery的数据缓存系统
jQuery.Data源码
jQuery.data的是jQuery的数据缓存系统
jQuery.data的是jQuery的数据缓存系统。它的主要作用就是为普通对象或者DOM元素添加数据。
1 内部存储原理
这个原理很简单,原本要添加在DOM元素本身的数据,现在被集中的存储在cache集合中。它们之间靠一个从开始的数字键来联系着。这样DOM元素就不会像以前那么笨重了,更不会出现以前那种循环引用而引起的内存泄漏。现在DOM只需要保存好这个数字键值即可。这个属性值被保存在DOM元素的一个属性里,该属性名是由jQuery.expando生成的。
2 Data构造函数
Object.defineProperty( this.cache = {}, 0, {
get: function() {
return {};
}
});
首先来看Object.defineProperty函数,它的作用为:将属性添加到对象,或修改现有属性的特性。那我们先来看下ECMAScript5中的属性。
2.1 ECMAScript5中的属性
ECMAScript5中有两种属性:数据属性和访问器属性。
2.1.1 数据属性:
数据属性包含一个数据值的位置,在这个位置可以读取和写入值。有4种特性用来限制其行为。
①[[configurable]]
能否通过delete删除属性,能否修改属性的特性,能否把属性改为访问器属性。默认为true。

var obj={name:"abc"};
Object.defineProperty(obj,"name",{
configurable:false
});
console.log(obj.name);
delete obj.name;
console.log(obj.name);
Object.defineProperty(obj,"name",{
configurable:true
});

注意,一旦将 configurable 设为false,就再也设置不回去了。而且还会报错。
②[[enumerable]]
在for-in循环是否能获取到属性。默认为true。ECMAScript规定,由程序员定义的属性的该特性都为true。
③[[writable]]
能否修改属性的值。默认为true。

var obj={name:"abc"};
Object.defineProperty(obj,"name",{
writable:false
});
console.log(obj.name);
obj.name="111";
console.log(obj.name);

④[[value]]
属性值所在的地方。读取属性值的时候获取的就是它,写属性值的时候也是往这里写。

var obj={name:"abc"};
console.log(obj.name);
Object.defineProperty(obj,"name",{
value:111
});
console.log(obj.name);

2.1.2访问器属性
访问器属性不包含实际的属性值,它包含两个函数(getter和setter)
①[[get]]
读取属性时调用的函数。默认为undefined
②[[set]]
写入属性时调用的函数。默认为undefined

var obj={};
Object.defineProperties(obj,{
name:{
get:function () {
return obj["_name"];
},
set:function (name) {
if(name != "C#"){
obj["_name"]=name;
}
}
},
label:{
get:function () {
return "你不能改变我!!!";
}
}
});
obj.name="JavaScript";
console.log(obj.name);
obj.label="我偏要改变你!!!";
console.log(obj.label);

上面给cache的属性0,只给了get属性。所以不能为该属性赋值。只能获取。
this.expando = jQuery.expando + Math.random();
这个expando就是用来为DOM元素或者对象存储在cache中的键的。即它将作为DOM元素的一个属性被存储这。
红色画框内的属性名就是由上面的语句生成的,指明div1的属性存储在cache的1属性中。
Data.uid = 1;
该属性表示cache的属性将从1开始自增。因为0已经被这个冻结的空JSON占用了,所以从1开始。我们下次再为某DOM元素添加属性时,它将被保存在cache的2属性中。
3 允许的添加属性的元素
Data.accepts = function( owner ) {
return owner.nodeType ?
owner.nodeType === 1 || owner.nodeType === 9 : true;
};
这段代码写的非常干练。表示如果owner是DOM元素则只有ELEMENT_NODE和DOCUMENT_NODE两种元素能添加属性,如果owner是一个对象,则都可以添加属性。
4 原型属性
4.1 key: function( owner ) {
if ( !Data.accepts( owner ) ) {
return 0;
}
如果owner不能被添加data,则返回cache的第0个元素。
unlock = owner[ this.expando ];
这里获取的就是
如果能从owner中找到这个属性,则说明以前为它添加过值,也就是说,它已经拥有了一个在cache中的key。

if ( !unlock ) {
unlock = Data.uid++;
try {
descriptor[ this.expando ] = { value: unlock};
Object.defineProperties( owner, descriptor );
} catch ( e ) {
descriptor[ this.expando ] = unlock;
jQuery.extend( owner, descriptor );
}
}

如果找不到,则说明是第一次为owner添加属性,则要创建一个key。这个key就是在Data的uid的基础上加1.Data的uid是一个静态属性。这样就能记录前一个元素的key是多少,这次的key又应该是多少。try块里面为owner(即DOM元素或者对象)添加它在cache中的索引。这里会出现兼容性的问题。在Android系统<4时会出现安全问题,因此jQuery使用extend静态方法将descriptor扩展到owner上面。
if ( !this.cache[ unlock ] ) {
this.cache[ unlock ] = {};
}
这里为owner对应在cache中的key赋值一个Object。
这个的key方法的作用就是为DOM元素创建属性,为cache中对应的key赋值(空对象)。
key返回的是这个unlock,即owner对象在cache中对应的key。
4.2 set: function( owner, data, value ) {
unlock = this.key( owner ),
cache = this.cache[ unlock ];
第一句不用解释,第二句或者cachekey值。以上图所示,则这里的cache目前还是{},因为在此之前还没有为div1添加过属性。
if ( typeof data === "string" ) {
cache[ data ] = value;
我们下面的代码走的就是这里:
$("#div1").data("name","div1");
但是我们有很多属性要设置的时候,
$("#div1").data({name:"div1",from:"0",to:"100"});
jQuery的处理方式是这样的:

// Handle: [ owner, { properties } ] args
} else {
// Fresh assignments by object are shallow copied
if ( jQuery.isEmptyObject( cache ) ) {
jQuery.extend( this.cache[ unlock ], data );
// Otherwise, copy the properties one-by-one to the cache object
} else {
for ( prop in data ) {
cache[ prop ] = data[ prop ];
}
}
}

其实这里个人以为不用再判断了,因为extend里面也是用for循环将data的属性扩展到cache中的。
4.3 get: function( owner, key ) {
var cache = this.cache[ this.key( owner ) ];
return key === undefined ? cache : cache[ key ];
获取属性,代码非常简单。如果key不存在则返回cache对象。
4.4 access: function( owner, key, value ) {
这里对get和set方法的统一访问。
4.5 remove: function( owner, key ) {
unlock = this.key( owner ),
cache = this.cache[ unlock ];
获取owner的在cache中的数据对象,this.key返回的是owner在cache中的key。
if ( key === undefined ) {
this.cache[ unlock ] = {};
如果不指定要删除那个属性的话,jQuery会删除owner所有的数据属性。
否则再判断key是不是数组,
if ( jQuery.isArray( key ) ) {
name = key.concat( key.map( jQuery.camelCase ) );
}
是数组的话,将key数组和用key的每一项转驼峰后的数组合并,即:
$("#div1").remove(["one_key","two_key"]);
经过上面的代码,key为变为["one_key","two_key","oneKey","twoKey"]。后面会将这4个属性都删除掉。
那如果key不是数组:

camel = jQuery.camelCase( key );
if ( key in cache ) {
name = [ key, camel ];
} else {
name = camel;
name = name in cache ?
[ name ] : ( name.match( core_rnotwhite ) || [] );
}

同样先输转驼峰,然后判断key是否存在,不存在则判断key的驼峰形式是否存在,后面的正则表达式用于去除驼峰形式前后的空格。
当这些情况过滤完之后,进行删除操作:
i = name.length;
while ( i-- ) {
delete cache[ name[ i ] ];
}
在while循环里面使用delete进行删除。
4.6 hasData: function( owner ) {
cache中是否拥有woner的数据对象。
4.7 discard: function( owner ) {
删除cache中的woner的数据对象。
5 创建两个私有的cache
data_user = new Data();
data_priv = new Data();
所以,我们在jQuery的外面不能直接拿到这个cache。因为它是jQuery的局部变量。data_user供开发人员使用,data_priv供jQuery内部使用。
6 创建对外接口(工具方法和原型方法)
由于Data构造器是jQuery私有的,我们在外面不能访问到,所以前面的那些方法,我们也不能直接访问,jQuery在这里,给我们提供了一些接口。来操作data_user,为DOM元素和Object进行属性操作。工具方法非常简单只是对data_user方法的封装而已。我们主要看下原型方法。
jQuery.fn.extend({
data: function( key, value ) {
设值和取值都会进入上面的方法。
这里有这样一个思想,如果是设值的时候,则给选集中所有的选项设值,如果获取值的时候,只获取第一个选项的值。

if ( key === undefined ) {
if ( this.length ) {
data = data_user.get( elem );
if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
attrs = elem.attributes;
for ( ; i < attrs.length; i++ ) {
name = attrs[ i ].name;
if ( name.indexOf( "data-" ) === 0 ) {
name = jQuery.camelCase( name.slice(5) );
dataAttr( elem, name, data[ name ] );
}
}
data_priv.set( elem, "hasDataAttrs", true );
}
}
return data;
}

在第3行,已经取到cache中elem对应的属性了,下面jQuery由将elem的attributes里的所有属性添加到elem的 。
hasDataAttrs属性是我们自己添加,因为下面这段代码只需要执行一次即可。代码第6行,获取elem所有的属性;
这个NamedNodeMap类型,我们平时很少直接用它,它和NodeList,HTMLCollection一样都是“动态”的。NamedNodeMap集合中的每一项都是Attr类型,Attr对象有3个属性:name,value和specified。
在下面的for循环里面,就检测这个name属性中是否含有"data-"前缀。有的话就去掉它,并且将剩余部分转为驼峰形式。
如果key不存在,则表示获取选集中第一个选项的所有属性值。elem表示第一个选项。
if ( typeof key === "object" ) {
return this.each(function() {
data_user.set( this, key );
});
}
对应这种形式:
$("#div1").remove(["one_key","two_key"]);
jQuery.data的是jQuery的数据缓存系统的更多相关文章
- jQuery源码解读 - 数据缓存系统:jQuery.data
jQuery在1.2后引入jQuery.data(数据缓存系统),主要的作用是让一组自定义的数据可以DOM元素相关联——浅显的说:就是让一个对象和一组数据一对一的关联. 一组和Element相关的数据 ...
- Memcached 数据缓存系统
Memcached 数据缓存系统 常用命令及使用:http://www.cnblogs.com/wayne173/p/5652034.html Memcached是一个自由开源的,高性能,分布式内存对 ...
- 第十七课:js数据缓存系统的原理
这一章主要讲的是jQuery的缓存系统的历史发展,以及他自己的框架的缓存系统的实现.都是源码解析. 我就挑几个重点讲下: (1)jQuery的缓存机制的原理 jQuery的缓存机制实现的原理是在元素中 ...
- Memcache,Redis,MongoDB(数据缓存系统)方案对比与分析
mongodb和memcached不是一个范畴内的东西.mongodb是文档型的非关系型数据库,其优势在于查询功能比较强大,能存储海量数据.mongodb和memcached不存在谁替换谁的问题. 和 ...
- jQuery数据缓存$.data 的使用以及源码解析
一.实现原理: 对于DOM元素,通过分配一个唯一的关联id把DOM元素和该DOM元素的数据缓存对象关联起来,关联id被附加到以jQuery.expando的值命名的属性上,数据存储在全局缓存对象jQu ...
- jQuery 源码分析(十) 数据缓存模块 data详解
jQuery的数据缓存模块以一种安全的方式为DOM元素附加任意类型的数据,避免了在JavaScript对象和DOM元素之间出现循环引用,以及由此而导致的内存泄漏. 数据缓存模块为DOM元素和JavaS ...
- jQuery 2.0.3 源码分析 数据缓存
历史背景: jQuery从1.2.3版本引入数据缓存系统,主要的原因就是早期的事件系统 Dean Edwards 的 ddEvent.js代码 带来的问题: 没有一个系统的缓存机制,它把事件的回调都放 ...
- jQuery.data() 存储数据
jQuery.data() 的实现方式 jQuery.data() 的作用是为普通对象或 DOM Element 附加数据. 以下将分三个部分分析事实上现方式: 1. 用name和value为对象附加 ...
- jQuery.Data源码
jQuery.data的是jQuery的数据缓存系统.它的主要作用就是为普通对象或者DOM元素添加数据. 1 内部存储原理 这个原理很简单,原本要添加在DOM元素本身的数据,现在被集中的存储在cach ...
随机推荐
- mysql在关闭时的几个阶段
mysql关闭的大致过程 1.The shutdown process is initiated 初始化关机过程有许多种方法1.mysqladmin shutdown ; 2.kill pid_of_ ...
- 研究 UIActivityViewController
研究 UIActivityViewController 发布于:2014-04-25 09:51阅读数:5903 特定的编程语言,如 Lisp.lo 和 Mathematica 都是同像性的(homo ...
- SGU 294 He's Circles
题意:一个项链有n个珠子,每个珠子为黑色或白色.问有多少种不同的项链? 注意,n的数量十分大,因此,我们枚举i(1<=i<=n),令L=n/i,求出L的欧拉函数,则这些数和L互质,因此gc ...
- Java中的随机数生成器:Random,ThreadLocalRandom,SecureRandom(转)
文中的 Random即:java.util.Random,ThreadLocalRandom 即:java.util.concurrent.ThreadLocalRandomSecureRandom即 ...
- Non-unique Elements
Non-unique Elements You are given a non-empty list of integers (X). For this task, you should return ...
- unix c 10
网络常识: OSI 7层模型 TCP模型 IP和端口 IP是用来定位网络中的计算机,端口用来代表 计算机中的某个进程. IP 有点分十进制 和 十六进制的两种表示方式,底层 ...
- Kafka在Linux环境下搭建过程
准备工作 Kafka集群是把状态保存在Zookeeper中的,首先要搭建Zookeeper集群.由于我们之前的分布式系统中已经安装zookeeper服务,这里不进行zookeeper安装教程以及应用教 ...
- [转]Laravel 4之控制器
Laravel 4之控制器 http://dingjiannan.com/2013/laravel-controller/ 控制器 通常Laravel控制器文件放在app/controllers/目录 ...
- SAX解析和生成XML文档
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本人声明.否则将追究法律责任. 作者: 永恒の_☆ 地址: http://blog.csdn.net/chenghui031 ...
- HDU 1863:畅通project(带权值的并查集)
畅通project Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...