jQuery源码04 data() : 数据缓存
/*
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() : 数据缓存的更多相关文章
- jQuery 源码分析(十) 数据缓存模块 data详解
jQuery的数据缓存模块以一种安全的方式为DOM元素附加任意类型的数据,避免了在JavaScript对象和DOM元素之间出现循环引用,以及由此而导致的内存泄漏. 数据缓存模块为DOM元素和JavaS ...
- jQuery 源码分析(十三) 数据操作模块 DOM属性 详解
jQuery的属性操作模块总共有4个部分,本篇说一下第2个部分:DOM属性部分,用于修改DOM元素的属性的(属性和特性是不一样的,一般将property翻译为属性,attribute翻译为特性) DO ...
- 【菜鸟学习jquery源码】数据缓存与data()
前言 最近比较烦,深圳的工作还没着落,论文不想弄,烦.....今天看了下jquery的数据缓存的代码,参考着Aaron的源码分析,自己有点理解了,和大家分享下.以后也打算把自己的jquery的学习心得 ...
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
- jQuery源码分析系列(38) : 队列操作
Queue队列,如同data数据缓存与Deferred异步模型一样,都是jQuery库的内部实现的基础设施 Queue队列是animate动画依赖的基础设施,整个jQuery中队列仅供给动画使用 Qu ...
- 读jQuery源码 - Callbacks
代码的本质突出顺序.有序这一概念,尤其在javascript——毕竟javascript是单线程引擎. javascript拥有函数式编程的特性,而又因为javascript单线程引擎,我们的函数总是 ...
- jQuery源码笔记(一):jQuery的整体结构
jQuery 是一个非常优秀的 JS 库,与 Prototype,YUI,Mootools 等众多的 Js 类库相比,它剑走偏锋,从 web 开发的实用角度出发,抛除了其它 Lib 中一些中看但不实用 ...
- jQuery源码分析-01总体架构
1. 总体架构 1.1自调用匿名函数 self-invoking anonymous function 打开jQuery源码,首先你会看到这样的代码结构: (function( window, und ...
- jquery 源码学习(一)
从上边的注释看,jQuery的源码结构相当清晰.条理,不像代码那般晦涩和让人纠结 1. 总体架构 1.1 自调用匿名函数 self-invoking anonymous function 打开jQ ...
随机推荐
- Gcc/MinGW/Cygwin/Msys 分别是什么?
一.GCC的历史 GCC是一个原本用于Unix-like系统下编程的编译器. 不过,现在GCC也有了许多Win32下的移植版本. 所以,也许对于许多Windows开发者来说,GCC还是一个比较陌生的东 ...
- django session深入
转至原文 https://www.cnblogs.com/zhaof/p/6281468.html 基于cookie做用户验证时:敏感信息不适合放在cookie中 session依赖cookie s ...
- [luoguP4302] [SCOI2003] 字符串折叠 解题报告(区间DP)
题目链接:https://www.luogu.org/problemnew/show/P4302 题解: 我们考虑折叠一个区间里的字符串,怎么样才是最优的 1.把这个区间分成几部分分别折叠 2.把这个 ...
- PostgreSQL环境中查看SQL执行计划示例
explain analyze ,format,buffers, format :TEXT, XML, JSON, or YAML. EXPLAIN (ANALYZE,buffers,format ...
- S-Nim POJ - 2960 Nim + SG函数
Code: #include<cstdio> #include<algorithm> #include<string> #include<cstring> ...
- Ubuntu(kali)开启mysql远程连接
Linux 默认关闭mysql的远程连接,编辑 /etc/mysql/my.cnf 文件, 把里面的 bind-address = 127.0.0.1 改成 bind-address = 0.0.0. ...
- 使用 AutoHotKey 配合Win10分屏功能
Win+tab键 建立新的虚拟桌面 使用笔记本电脑的触摸板,用四个手指滑的话就可以在虚拟桌面间切换 那么就映射一下, 要是能一键切换的话就相当于是个"老板键"了 1.安装AutoH ...
- [译] 我最终是怎么玩转了 Vue 的作用域插槽
原文链接:https://juejin.im/post/5c8856e6e51d456b30397f31#comment 原文地址:How I finally got my head around S ...
- caioj 1086 动态规划入门(非常规DP10:进攻策略)
一开始看到题目感觉很难 然后看到题解感觉这题贼简单,我好像想复杂了 就算出每一行最少的资源(完全背包+二分)然后就枚举就好了. #include<cstdio> #include<a ...
- ArcGIS api for javascript——设置自定义范围和空间参考
描述 这个示例展示了在创建地图时如果定义一个自定义的范围和空间参考. 在 ArcGIS JavaScript API的1.0和1.1版本,任何要使用的地图服务图层都需要和地图的空间参考一致.1.2版本 ...