jquery.Data()

/*$('#div1').attr('name','hello');
	
	alert( $('#div1').attr('name') );*/
	
	document.getElementById('div1').setAttribute('name','hello');
	alert( document.getElementById('div1').getAttribute('name') );
	
	
	/*$('#div1').prop('name','hello');
	
	alert( $('#div1').prop('name') );*/
	
	document.getElementById('div1')['name'] = 'hello';
	alert( document.getElementById('div1')['name'] );

    /*document.getElementById('div1').name = 'hello';
	alert( document.getElementById('div1').name );*/

//上面两种方式是不适合在元素身上设置大量的数据,合适设置一些简单的数据或者设置元素本身的属性

//DOM元素与对象之间互相引用,大部分浏览器就会出现内存泄漏

var oDiv = document.getElementById('div1');
var obj = {};

oDiv.name = obj;
obj.age = oDiv;//对象下的一个属性,引用了dom元素

$('#div1').attr('name',obj);==>这种情况下,如果对象属性再引用dom元素,就容易造成内容泄露
$('#div1').data('name',obj);==>而这种情况则不会存在内容泄露

内存泄露是指,浏览器占用内存越来越大,最后导致内存溢出,因为是因为一些变量没有得到释放,js的垃圾回收机制没有回收

//下面发方式使用的话,比如
			//var obj = { name : "hello" };
			
			Object.freeze(obj); //freeze,让obj不可修改,但是在android5一下版本这种方式是不起作用,所以得使用下面这种方式
			Object.defineProperty( obj = {}, 0, {//这只有get方法,没有set方法,是不可改的
					get: function() {
						return {};
					}
				});
			
			obj.name = 'hi';
			
			alert( obj.name );

//Object的defineProperty和defineProperties这两个方法在js中的重要性十分重要,主要功能就是用来定义或修改这些内部属性,与之相对应的getOwnPropertyDescriptor和getOwnPropertyDescriptors就是获取这行内部属性的描述。

 

html5:
dataset


<div id="div1" data-xiaomao-all="妙味" class="box" title="123">aaaa</div>

$('#div1').get(0).dataset.xiaomaoAll ==> 获取数据

 

//DOM元素与对象之间互相引用,大部分浏览器就会出现内存泄漏

			data_user = new Data();//对外的对象
			data_priv = new Data();//内部的对象

			function Data() {
				// Support: Android < 4,
				// Old WebKit does not have Object.preventExtensions/freeze method,
				// return new empty object instead with no [[set]] accessor
				Object.defineProperty( this.cache = {}, 0, {//这里的0是很多地方共用的,
					get: function() {
						return {};
					}
				});

				this.expando = jQuery.expando + Math.random();//唯一的标识
			}

			Data.uid = 1;

			Data.accepts = function( owner ) {
				// Accepts only:
				//  - Node
				//    - Node.ELEMENT_NODE
				//    - Node.DOCUMENT_NODE
				//  - Object
				//    - Any
				return owner.nodeType ?
					owner.nodeType === 1 || owner.nodeType === 9 : true;//判断的是节点类型
			};

			Data.prototype = {
				key: function( owner ) {
					// We can accept data for non-element nodes in modern browsers,
					// but we should not, see #8335.
					// Always return the key for a frozen object.
					if ( !Data.accepts( owner ) ) {//判断节点是否存在,没有分配的都会分配0,0是不可改的
						return 0;
					}

					var descriptor = {},
						// Check if the owner object already has a cache key
						unlock = owner[ this.expando ];

					// If not, create one
					if ( !unlock ) {//分配标识id,分配自定义属性expando
						unlock = Data.uid++;

						// Secure it in a non-enumerable, non-writable property
						try {
							descriptor[ this.expando ] = { value: unlock };//往元素上添加值,但是是不可改的,可读
							Object.defineProperties( owner, descriptor );

						// Support: Android < 4
						// Fallback to a less secure definition
						} catch ( e ) {
							descriptor[ this.expando ] = unlock;
							jQuery.extend( owner, descriptor );//这种方法有可能会被人为的修改掉
						}
					}

					// Ensure the cache object
					if ( !this.cache[ unlock ] ) {
						this.cache[ unlock ] = {};
					}

					return unlock;
				},
				set: function( owner, data, value ) {
					var prop,
						// There may be an unlock assigned to this node,
						// if there is no entry for this "owner", create one inline
						// and set the unlock as though an owner entry had always existed
						unlock = this.key( owner ),//先找到分配给改元素的uuid,
						cache = this.cache[ unlock ];//找到id后,根据缓存找到对应的cache的json

					// Handle: [ owner, key, value ] args
					if ( typeof data === "string" ) {//判断是否是字符串,如果是的话,就进行添加
						cache[ data ] = value;

					// Handle: [ owner, { properties } ] args
					} else {//如果data不是字符串,而是json的话,就会走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 ];
							}
						}
					}
					return cache;
				},
				get: function( owner, key ) {
					// Either a valid cache is found, or will be created.
					// New caches will be created and the unlock returned,
					// allowing direct access to the newly created
					// empty data object. A valid owner object must be provided.
					var cache = this.cache[ this.key( owner ) ];

					return key === undefined ?
						cache : cache[ key ];
				},
				access: function( owner, key, value ) {//根据参数的个数来操作是否是get还是set
					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) ) {

						stored = this.get( owner, key );

						return stored !== undefined ?
							stored : this.get( owner, jQuery.camelCase(key) );
					}

					// [*]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;
				},
				remove: function( owner, key ) {
					var i, name, camel,
						unlock = this.key( owner ),
						cache = this.cache[ unlock ];

					if ( key === undefined ) {//如果key不存在,则将元素身上所有的数据都清空
						this.cache[ unlock ] = {};

					} else {
						// Support array or space separated string of keys
						if ( jQuery.isArray( key ) ) {
							// If "name" is an array of keys...
							// When data is initially created, via ("key", "val") signature,
							// keys will be converted to camelCase.
							// Since there is no way to tell _how_ a key was added, remove
							// both plain key and camelCase key. #12786
							// This will only penalize the array argument path.
							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 {
								// If a key with the spaces exists, use it.
								// Otherwise, create an array by matching non-whitespace
								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 ) {
					if ( owner[ this.expando ] ) {
						delete this.cache[ owner[ this.expando ] ];
					}
				}
			};

			// These may be used throughout the jQuery core codebase
			data_user = new Data();
			data_priv = new 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.fn.extend({
				data: function( key, value ) {
					var attrs, name,
						elem = this[ 0 ],//第一个元素
						i = 0,
						data = null;

					// Gets all values
					if ( key === undefined ) {//如果key参数没有传,则会返回元素下所有的data
						if ( this.length ) {//判断是否有元素
							data = data_user.get( elem );//获取到第一个元素身上的data

							if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {//这里主要是html5的设置了data属性的
								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设置倒cache中
									}
								}
								data_priv.set( elem, "hasDataAttrs", true );
							}
						}

						return data;
					}

					// Sets multiple values
					if ( typeof key === "object" ) {//$('#div1').data({name:'hello',age:'30'});针对这种情况
						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 );//找转了驼峰的实现比如aaaAaaa
							if ( data !== undefined ) {
								return data;
							}

							// Attempt to "discover" the data in
							// HTML5 custom data-* attrs
							data = dataAttr( elem, camelKey, undefined );//找针对html5 data- 设置的
							if ( data !== undefined ) {
								return data;
							}

							// We tried really hard, but the data doesn't exist.
							return;
						}

						// Set the data...
						this.each(function() {//这里是设置
							/*
									$('#div1').data('nameAge','hi');
									$('#div1').data('name-age','hello');
									如果有上面两种情况,则会讲两个都设置为相同的,如果没有,则只会设置一个
									this.cache = {
										1 : {
											'nameAge' : 'hello',
											'name-age' : 'hello' 
										}
									}
							*/
							// 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 ) {//首先看data在cache是否已经存在,如果存在,则不会走if
					name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();//知道大写字母,将第一个转成小写
					data = elem.getAttribute( name );

					if ( typeof data === "string" ) {//看data是否是字符串,如果是字符串,则
						try {
							data = data === "true" ? true ://==>这里是true的字符串的话,就转类型true
								data === "false" ? false ://==>这里是false的字符串的话,就转类型false
								data === "null" ? null ://==>这里是null的字符串的话,就转类型null
								// Only convert to a number if it doesn't change the string
								+data + "" === data ? +data ://==>这里是数子的话,就转数字
								rbrace.test( data ) ? JSON.parse( data ) ://rbrace.test( data )判断传进来的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;
			}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值