/*
Implementation Summary 1. Enforce API surface and semantic compatibility with 1.9.x branch
2. Improve the module's maintainability by reducing the storage
paths to a single mechanism.
3. Use the same single mechanism to support "private" and "user" data.
4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
5. Avoid exposing implementation details on user objects (eg. expando properties)
6. Provide a clear path for implementation upgrade to WeakMap in 2014
*/
var data_user, data_priv,
rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
rmultiDash = /([A-Z])/g; function Data() {
// cache = {0:{} },并且这个0属性是不能被修改的。这个0是公用的。
Object.defineProperty( this.cache = {}, 0, {
get: function() {
return {};
}
});
//唯一标识,id
this.expando = jQuery.expando + Math.random();
}
/*
var cache = {
1 : { //同一个元素只有一个id
age : 30,
job : 'it',
'allName' : '妙味课堂'
},
2 : {
age : obj
}
*/
Data.uid = 1;//cache中可以累加的属性1,2,3 Data.accepts = function( owner ) {
// 1是元素,2是document,都是可以在cache中分配id的。
return owner.nodeType ?
owner.nodeType === 1 || owner.nodeType === 9 : true;
}; Data.prototype = {
//分配映射id或者0:空json
key: function( owner ) {//owner是document.body或者$('#div1')对象,
// 不是元素也不是document,就返回0,id就是0,在cache中返回空对象{},defineProperty中给cache定义的空对象。
if ( !Data.accepts( owner ) ) {
return 0;
}
var descriptor = {},
// 获取$('#div1')的属性this.expando的值,
unlock = owner[ this.expando ];
if ( !unlock ) {
unlock = Data.uid++;
try {
/*
descriptor={jQuery203089541586732714850.8840931279098725:{value:1}}
*/
descriptor[ this.expando ] = { value: unlock };
//给owner增加一个属性descriptor:json并且不能改变
Object.defineProperties( owner, descriptor ); // Support: Android < 4
// Fallback to a less secure definition
} catch ( e ) {
//兼容性:通过extend给owner增加{key:value}的键值对,这个可以被修改descriptor={jQuery203089541586732714850.8840931279098725:1}
descriptor[ this.expando ] = unlock;
jQuery.extend( owner, descriptor );
}
}
if ( !this.cache[ unlock ] ) {
this.cache[ unlock ] = {};//cache={1:{}}
}
return unlock;
},
//设置cache的值
set: function( owner, data, value ) {
var prop,
//找到这个元素的id和cache中的json
unlock = this.key( owner ),
cache = this.cache[ unlock ];//cache是某个id的json if ( typeof data === "string" ) {
cache[ data ] = value;//是字符串,就把key value加进去
//是json,$.data(document.body ,{ 'age' : 30 , 'job' : 'it' , 'allName' : '妙味课堂'});
} else {
// Fresh assignments by object are shallow copied
if ( jQuery.isEmptyObject( cache ) ) {
jQuery.extend( this.cache[ unlock ], data );//继承json过去
// Otherwise, copy the properties one-by-one to the cache object
} else {
for ( prop in data ) {
cache[ prop ] = data[ prop ];
}
}
}
return cache;
},
//获取cache中的值
get: function( owner, key ) {
var cache = this.cache[ this.key( owner ) ]; return key === undefined ?
cache : cache[ key ];
},
//set,get合体
access: function( owner, key, value ) {
var stored;
// In cases where either:
//
// 1. No key was specified
// 2. A string key was specified, but no value provided
//
// Take the "read" path and allow the get method to determine
// which value to return, respectively either:
//
// 1. The entire cache object
// 2. The data stored at the key
//
if ( key === undefined ||
((key && typeof key === "string") && value === undefined) ) {
       //没有key全部取出来,有key没有value取key
stored = this.get( owner, key ); return stored !== undefined ?
stored : this.get( owner, jQuery.camelCase(key) );
}
   //有key有value.key是字符串全部覆盖,key是json追加
// [*]When the key is not a string, or both a key and value
// are specified, set or extend (existing objects) with either:
//
// 1. An object of properties
// 2. A key and value
//
this.set( owner, key, value ); // Since the "set" path can have two possible entry points
// return the expected data based on which path was taken[*]
return value !== undefined ? value : key;
}, //移除cache
remove: function( owner, key ) {
var i, name, camel,
unlock = this.key( owner ),
cache = this.cache[ unlock ];//cache是某一个key的cache, if ( key === undefined ) {//不指定key,这个元素所有的都清空。
this.cache[ unlock ] = {}; } else {
// $.removeData(document.body , ['age','job','all-name']);
if ( jQuery.isArray( key ) ) {
//all-name找到allName
name = key.concat( key.map( jQuery.camelCase ) );
} else {
camel = jQuery.camelCase( key );
// Try the string as a key before any manipulation
if ( key in cache ) {
name = [ key, camel ];
} else {
// 转驼峰,去空格后在不在
name = camel;
name = name in cache ?
[ name ] : ( name.match( core_rnotwhite ) || [] );
}
} i = name.length;
while ( i-- ) {
delete cache[ name[ i ] ];
}
}
},
hasData: function( owner ) {
return !jQuery.isEmptyObject(
this.cache[ owner[ this.expando ] ] || {}
);
},
discard: function( owner ) {//删除1,2,这个整体
if ( owner[ this.expando ] ) {
delete this.cache[ owner[ this.expando ] ];
}
}
}; // These may be used throughout the jQuery core codebase
data_user = new Data();//cache就是依附在这个对象上
data_priv = new Data(); //对外提供的接口,通过$.直接调用。这个是方法的定义,准备给jQuery类调用的,里面的实现都是调用Data对象的实现。
jQuery.extend({
acceptData: Data.accepts, hasData: function( elem ) {
return data_user.hasData( elem ) || data_priv.hasData( elem );
}, data: function( elem, name, data ) {
return data_user.access( elem, name, data );
}, removeData: function( elem, name ) {
data_user.remove( elem, name );
}, // TODO: Now that all calls to _data and _removeData have been replaced
// with direct calls to data_priv methods, these can be deprecated.
//私有的,内部使用,不对外使用
_data: function( elem, name, data ) {
return data_priv.access( elem, name, data );
}, _removeData: function( elem, name ) {
data_priv.remove( elem, name );
}
}); //对外提供的接口,通过jQuery对象调用。设置一组元素时候是设置所有元素,获取元素只是获取第一个。
jQuery.fn.extend({
data: function( key, value ) {
var attrs, name,
elem = this[ 0 ],//如果是一组div,就只要第一个,
i = 0,
data = null; // Gets all values
if ( key === undefined ) {
if ( this.length ) {//$('#div1')找不到得到
data = data_user.get( elem );
//alert($('#div1').get(0).dataset.miaovAll);//h5特性,data-miaov-all="妙味"
//对h5特性的处理
if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
attrs = elem.attributes;//元素所有属性数组集合[title='123',class='box',data-miaov-all='苗圩',id='div1']
for ( ; i < attrs.length; i++ ) {
name = attrs[ i ].name;//属性的名字 if ( name.indexOf( "data-" ) === 0 ) {
//miaov-all转成miaoAll,js中不要出现横杆
name = jQuery.camelCase( name.slice(5) );
//存入cache
dataAttr( elem, name, data[ name ] );
}
}
data_priv.set( elem, "hasDataAttrs", true );
}
} return data;
} // Sets multiple values$('#div1').data({name:'hello',age:'30'});
if ( typeof key === "object" ) {
return this.each(function() {
data_user.set( this, key );
});
} return jQuery.access( this, function( value ) {
var data,
camelKey = jQuery.camelCase( key ); // The calling jQuery object (element matches) is not empty
// (and therefore has an element appears at this[ 0 ]) and the
// `value` parameter was not undefined. An empty jQuery object
// will result in `undefined` for elem = this[ 0 ] which will
// throw an exception if an attempt to read a data cache is made.
if ( elem && value === undefined ) {
// Attempt to get data from the cache
// with the key as-is
data = data_user.get( elem, key );
if ( data !== undefined ) {
return data;
} // Attempt to get data from the cache
// with the key camelized
data = data_user.get( elem, camelKey );
if ( data !== undefined ) {
return data;
} // Attempt to "discover" the data in
// HTML5 custom data-* attrs
data = dataAttr( elem, camelKey, undefined );
if ( data !== undefined ) {
return data;
} // We tried really hard, but the data doesn't exist.
return;
} // Set the data...
this.each(function() {
// First, attempt to store a copy or reference of any
// data that might've been store with a camelCased key.
var data = data_user.get( this, camelKey ); // For HTML5 data-* attribute interop, we have to
// store property names with dashes in a camelCase form.
// This might not apply to all properties...*
data_user.set( this, camelKey, value ); // *... In the case of properties that might _actually_
// have dashes, we need to also store a copy of that
// unchanged property.
if ( key.indexOf("-") !== -1 && data !== undefined ) {
data_user.set( this, key, value );
}
});
}, null, value, arguments.length > 1, null, true );
}, removeData: function( key ) {
return this.each(function() {
data_user.remove( this, key );
});
}
}); function dataAttr( elem, key, data ) {
var name; // If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
if ( data === undefined && elem.nodeType === 1 ) {
name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
data = elem.getAttribute( name ); if ( typeof data === "string" ) {
try {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
// Only convert to a number if it doesn't change the string
+data + "" === data ? +data :
rbrace.test( data ) ? JSON.parse( data ) :
data;
} catch( e ) {} // Make sure we set the data so it isn't changed later
data_user.set( elem, key, data );
} else {
data = undefined;
}
}
return data;
}

jQuery源码04 data() : 数据缓存的更多相关文章

  1. jQuery 源码分析(十) 数据缓存模块 data详解

    jQuery的数据缓存模块以一种安全的方式为DOM元素附加任意类型的数据,避免了在JavaScript对象和DOM元素之间出现循环引用,以及由此而导致的内存泄漏. 数据缓存模块为DOM元素和JavaS ...

  2. jQuery 源码分析(十三) 数据操作模块 DOM属性 详解

    jQuery的属性操作模块总共有4个部分,本篇说一下第2个部分:DOM属性部分,用于修改DOM元素的属性的(属性和特性是不一样的,一般将property翻译为属性,attribute翻译为特性) DO ...

  3. 【菜鸟学习jquery源码】数据缓存与data()

    前言 最近比较烦,深圳的工作还没着落,论文不想弄,烦.....今天看了下jquery的数据缓存的代码,参考着Aaron的源码分析,自己有点理解了,和大家分享下.以后也打算把自己的jquery的学习心得 ...

  4. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

  5. jQuery源码分析系列(38) : 队列操作

    Queue队列,如同data数据缓存与Deferred异步模型一样,都是jQuery库的内部实现的基础设施 Queue队列是animate动画依赖的基础设施,整个jQuery中队列仅供给动画使用 Qu ...

  6. 读jQuery源码 - Callbacks

    代码的本质突出顺序.有序这一概念,尤其在javascript——毕竟javascript是单线程引擎. javascript拥有函数式编程的特性,而又因为javascript单线程引擎,我们的函数总是 ...

  7. jQuery源码笔记(一):jQuery的整体结构

    jQuery 是一个非常优秀的 JS 库,与 Prototype,YUI,Mootools 等众多的 Js 类库相比,它剑走偏锋,从 web 开发的实用角度出发,抛除了其它 Lib 中一些中看但不实用 ...

  8. jQuery源码分析-01总体架构

    1. 总体架构 1.1自调用匿名函数 self-invoking anonymous function 打开jQuery源码,首先你会看到这样的代码结构: (function( window, und ...

  9. jquery 源码学习(一)

    从上边的注释看,jQuery的源码结构相当清晰.条理,不像代码那般晦涩和让人纠结   1. 总体架构 1.1 自调用匿名函数 self-invoking anonymous function 打开jQ ...

随机推荐

  1. java9新特性-9-语法改进:try语句

    1. 使用举例 在java8 之前,我们习惯于这样处理资源的关闭:     java 8 中,可以实现资源的自动关闭,但是要求执行后必须关闭的所有资源必须在try子句中初始化,否则编译不通过.如下例所 ...

  2. Ionic2中的Navigation.md

    1. 概述 为了能够得到同原生应用类似的导航效果,Ionic创建了几个navagation组件来实现pages之间的导航操作,这种导航跟原生Angular2中的route机制是不一样的,我们可以借助于 ...

  3. exsi从磁盘中加载虚拟机

    e

  4. ORM原理

    原理: 1.实现JavaBean的属性到数据库表的字段的映射:        --通过配置文件将JavaBean的属性与数据库表的字段的关联起来 2.映射关系:   一对多,多对一等 持久层(Pers ...

  5. 第一性原理:First principle thinking是什么?

    作者:沧海桑田链接:https://www.zhihu.com/question/40550274/answer/225236964来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  6. [JLOI2011]飞行路线 分层图最短路

    题目描述: Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公司一共在nn个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一 ...

  7. Ubuntu命令行快捷启动Pycharm

    我pycharm安装目录为/home/dell/pycharm-community-2018.1.2/bin.那么安装完成之后系统不会给pycharm添加系统路径,只有把终端切换到安装目录/home/ ...

  8. uva 1292 树形dp

    UVA 1292 - Strategic game 守卫城市,城市由n个点和n-1条边组成的树,要求在点上安排士兵,守卫与点相连的边.问最少要安排多少士兵. 典型的树形dp.每一个点有两个状态: dp ...

  9. 大型网站架构之JAVA中间件

    中间件就是在大型网站中,帮助各子模块间实现互相访问,消息共享或统一访问等功能的软件产品.常见的有: 远程服务框架中间件:主要解决各子模块之间互相访问的问题. 消息队列中间件:主要解决各子模之间消息共享 ...

  10. 服务器性能监控tips

    一.tops 第一行 当前时间/已运行时间/登录用户数/最近 5 10 15分钟平均负载(平均进程数 cat /proc/loadavg) 除了前3个数字表示平均进程数量外,后面的1个分数,分母表示系 ...