Maison  >  Article  >  interface Web  >  Analyse approfondie de l'utilisation et des précautions des fonctions jQuery.data, jQuery._data et des instances de données

Analyse approfondie de l'utilisation et des précautions des fonctions jQuery.data, jQuery._data et des instances de données

巴扎黑
巴扎黑original
2017-06-20 10:06:331701parcourir

Question 1 : Quel est le format des données enregistrées dans jQuery ? Quelle est la différence entre les données enregistrées via les données et le format d'événement enregistré ?

Regardez d'abord le code suivant :

    $._data($("#data")[0],"name","qinliang");
	    $._data($("#data")[0],"sex","male");
	   $("#data").click(function()
	   {
		 console.log("click1");
	   });
	    $("#data").click(function()
	   {
		 console.log("click2");
	   });
	    $("#data").mouseover(function()
	   {
		 console.log("click");
	   });
	   //data保存的数据通过result.name,result.sex访问
	   //在DOM上面绑定的事件函数如果要访问,可以通过result.events.click,result.events.mouseover不过返回的都是数组
	   //特别注意:这里是通过_data方法保存的数据!
	   var result=$._data($("#data")[0]);
	   console.log(result);

remarque : à partir de cette image, nous savons que les données enregistrées via _data sont stockées sur l'objet DOM. L'objet obtenu via $._data(document.getElementById("data")) est accessible via le. nom de la clé. to; mais pour les fonctions liées aux événements, elles ne sont accessibles que via $._data(document.getElementById("data")).events["click"].

Question 2 : Quel est le format des données enregistrées par l'utilisateur via $.data ?

Nous modifions le code ci-dessus en :

 $.data($("#data")[0],"name","qinliang");
	    $.data($("#data")[0],"sex","male");
	   $("#data").click(function()
	   {
		 console.log("click1");
	   });
	    $("#data").click(function()
	   {
		 console.log("click2");
	   });
	    $("#data").mouseover(function()
	   {
		 console.log("click");
	   });
	   //data保存的数据通过result.name,result.sex访问
	   //在DOM上面绑定的事件函数如果要访问,可以通过result.events.click,result.events.mouseover不过返回的都是数组
	   //特别注意:这里是通过_data方法保存的数据!
	   var result=$.data($("#data")[0]);
	   console.log(result);

Remarque : Passé Dans cette image, vous constaterez que les données enregistrées par l'utilisateur, c'est-à-dire les données enregistrées via la méthode $.data, n'enregistreront que des données personnalisées, tandis que les données internes telles que l'inscription à un événement ne sont pas dans le champ d'application de données utilisateur !
Question 3 : Quelles données sont des données internes de jQuery et quelles données sont des données définies par l'utilisateur ?

Réponse : L'enregistrement d'un événement ou _data est appelé en interne via jQuery, et le format de données enregistré est le première image, et les données enregistrées par l'utilisateur via data sont au format de la deuxième image, qui ne contient que des données définies par l'utilisateur !

Question 4 : Nous nous lions sur l'instance jQuery Comment les données sont-elles enregistrées dans la couche inférieure ? Le format est-il le même que celui de l'enregistrement des données via jQuery

Nous modifions l'exemple ci-dessus en une méthode d'instance :

 $("#data").data("name","qinliang");
	   $("#data").data("sex","male");
	   $("#data").click(function()
	   {
		 console.log("click1");
	   });
	    $("#data").click(function()
	   {
		 console.log("click2");
	   });
	    $("#data").mouseover(function()
	   {	
	   })
	 //先获取jQuery.expando才能去获取钥匙,所以jQuery.expando是最重要的,他是打开大门的第一步!
	   var internalKey=jQuery.expando;
	 //通过jQuery.expando去获取钥匙
	   var id= $("#data")[0][internalKey];
	   //获取到钥匙以后,就可以去jQuery.cache这个仓库去获取到数据了!
	   var result=jQuery.cache[id];
	   //获取到的数据
	   console.log(result);

remarque : nous savons à partir de cette image, le format de données enregistré en bas de l'objet instance a trois champs , le champ de données enregistre les données de l'utilisateur ; les événements enregistrent les événements de l'objet ; le champ du gestionnaire est la fonction de rappel générale . !
Question 5 : Qu'est-ce que c'est que jQuery.expando ?

	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" )//每次保存数据的时候会生产一个expando?,具有随机性?

Un nombre aléatoire sera-t-il généré à chaque fois que les données sont enregistrées ? En fait, non, il sera seulement généré ? une fois lorsqu'elle est appelée pour la première fois. Cela doit être noté, donc peu importe le nombre de fois que vous appelez la méthode data, la valeur sera la même !

Les nombres aléatoires générés par le code suivant sont les pareil.

   var result1=jQuery.expando;
   var result2=jQuery.expando;
   console.log(result1);
   console.log(result2);//result1和result2是相等的,因为只在第一次调用的时候产生一次随机数,以后就是直接访问前面的随机数了,因为是全局变量非函数!

remarque : tous les DOM utilisent le même expando pour enregistrer les données, c'est-à-dire que chaque DOM a le même nom d'attribut jQuery.expando

Question ! 5 : Puisque expando est unique, comment faire en sorte que chaque DOM ait une clé différente ?

	if ( isNode ) {
			id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
		} else {
			id = internalKey;
		}

remarque : ce morceau de code nous dit que bien que le nom de l'attribut soit le même , la valeur de l'attribut est C'est différent et l'unicité est garantie via jQuery.guid.

Question 6 : Qu'est-ce que jQuery.guid ? Pourquoi peut-il garantir que chaque élément du DOM a une clé unique
La fonction proxy traitera le guid lors de la génération d'une nouvelle fonction, donc sa valeur ? est incrémenté :

proxy: function( fn, context ) {
		var args, proxy, tmp;
		if ( typeof context === "string" ) {
			tmp = fn[ context ];
			context = fn;
			fn = tmp;
		}
		// Quick check to determine if target is callable, in the spec
		// this throws a TypeError, but we will just return undefined.
		if ( !jQuery.isFunction( fn ) ) {
			return undefined;
		}
		// Simulated bind
		args = slice.call( arguments, 2 );
		proxy = function() {
			return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
		};
		// Set the guid of unique handler to the same of original handler, so it can be removed
		proxy.guid = fn.guid = fn.guid || jQuery.guid++;//对新的函数设置guid++保证每一个通过jQuery处理的函数都有一个guid值,而且唯一!
		return proxy;
	}

Dans la méthode jQuery.event.add, un nouveau guid sera défini pour chaque fonction liée, à condition qu'elle n'ait pas de valeur guid :

if ( !handler.guid ) {//没有guid值添加
	handler.guid = jQuery.guid++;
}

Dans l'instance sur la fonction, si une fonction ne sera appelée qu'une seule fois, alors définissez la valeur GUID (en fait la fonction proxy)

if ( one === 1 ) {
			origFn = fn;
			fn = function( event ) {
				// Can use an empty set, since event contains the info
				jQuery().off( event );
				return origFn.apply( this, arguments );
			};
			// Use same guid so caller can remove using origFn
			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );//为函数都唯一生产guid,其它函数通过调用上面的jQuery.event.add保证唯一!
		}

Lorsque l'instance enregistre les données, pour chaque objet DOM Le même attribut , c'est-à-dire que l'attribut jQuery.expando définit une valeur de clé unique :

if ( isNode ) {
		id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
		} else {
			id = internalKey;
		}

remarque : jQuery.guid est utilisé pour la liaison d'événements et la sauvegarde des données, pour chaque DOM de données enregistrées et chaque La fonction de rappel d'un événement lié se voit attribuer une valeur guid unique !
Question 7 : La clé est obtenue, alors où est l'entrepôt ?

jQuery.cache={},
cache = isNode ? jQuery.cache : elem,

De là, nous savons que si c'est un objet DOM, alors l'entrepôt est jQuery.cache, si c'est un objet js, alors l'entrepôt est lui-même
Question 8 : La clé est obtenue, l'entrepôt est également disponible, et les données peuvent être ! obtenu, alors Où sont stockées mes données ?

Comme nous l'avons dit ci-dessus : le format de données enregistré en bas de l'objet instance a trois champs, respectivement, le champ de données enregistre les données de l'utilisateur ; l'événement de données de l'objet ; le champ du gestionnaire est une fonction de rappel générale ! Alors, comment mes données sont-elles enregistrées sous le champ de données :

	if ( !cache[ id ] ) {//如果DOM的仓库还没存在,也就是没调用过data方法,那么我们初始化仓库!
		// Avoid exposing jQuery metadata on plain JS objects when the object
		// is serialized using JSON.stringify
		cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
	}
	// An object can be passed to jQuery.data instead of a key/value pair; this gets
	// shallow copied over onto the existing cache
	if ( typeof name === "object" || typeof name === "function" ) {//如果是object或者function那么我们让仓库继承他所有的属性
		if ( pvt ) {
			cache[ id ] = jQuery.extend( cache[ id ], name );//jQuery内部的数据直接保存在仓库里面
		} else {
			cache[ id ].data = jQuery.extend( cache[ id ].data, name );//如果是自定义数据保存在仓库的data域下面!
		}
	}

remarque : les données utilisateur sont enregistrées sous le champ de données. de l'entrepôt. Si les données jQuery sont stockées dans l'entrepôt, il n'est pas nécessaire d'ouvrir un nouvel espace !
Question 9 : Comment juger s'il faut obtenir des données ou les enregistrer ?

     //获取到数据仓库,cache是仓库,id是钥匙!
	thisCache = cache[ id ];
	// jQuery data() is stored in a separate object inside the object's internal data
	// cache in order to avoid key collisions between internal data and user-defined
	// data.
	//如果是用户数据,而且没有data域,那么开启data域
	if ( !pvt ) {
		if ( !thisCache.data ) {
			thisCache.data = {};
		}
		thisCache = thisCache.data;
	}
   //到达这里,如果是用户数据已经获取到仓库的data域,内部数据获取到仓库!
	if ( data !== undefined ) {
		//保存数据成功!
		thisCache[ jQuery.camelCase( name ) ] = data;
	}
	// Check for both converted-to-camel and non-converted data property names
	// If a data property was specified
	//如果name是string那么获取仓库中数据返回,否则直接返回仓库本身!
	if ( typeof name === "string" ) {
		// First Try to find as-is property data
		ret = thisCache[ name ];
		// Test for null|undefined property data
		if ( ret == null ) {
			// Try to find the camelCased property
			ret = thisCache[ jQuery.camelCase( name ) ];
		}
	} else {
		ret = thisCache;
	}
	return ret;

remarque : Si des données existent, cela signifie oui. Enregistrez les données. À ce stade, enregistrez les données dans un domaine spécifique. Les données utilisateur sont sous le domaine de données de l'entrepôt, et les données internes sont directement dans l'entrepôt ! S'il s'agit d'obtenir des données, si le nom est une chaîne, alors obtenez le contenu spécifique dans l'entrepôt, sinon il le fera directement. retourner à l'entrepôt lui-même !
Question 10 : Est-il possible dans Objet d'enregistrer des données dessus

          var obj=new Object();//在object对象上面保存数据!
	   jQuery.data(obj,"name","qinliang");
	   jQuery.data(obj,"sex","female");
	  var result=jQuery.data(obj,"sex");
	  console.log(result);//打印sex

remarque : Cette façon de sauvegarder les données n'est pas déclenchée par le DOM, mais par objet JS. Cependant, la méthode data appartient à l'objet jQuery, , donc la méthode data ne peut pas être appelée directement , mais la méthode jQuery.data peut être appelée. Cette méthode peut également enregistrer des données sur l'objet Object ! un aperçu du format de données enregistré de cette manière. Comment ça se passe :

 var obj=new Object();
	   jQuery.data(obj,"name","qinliang");
	   var key=jQuery.expando;
	   //对于Object对象,钥匙就是jQuery.expando
	   var warehouse=obj;
	   //获取仓库,Object对象的仓库是自身
	   var data= warehouse[key];
	   //获取数据
	   console.log(data);

note:通过该图你会发现,通过object对象保存的数据也是在data域下面,同时为了保证数据的安全性,该元素的toJson方法是空的,也表示无法对数据进行json格式化!
问题11:如果是jQuery内部的数据那么不是保存在data域下面?我想确认一下?

   //内部数据是只能通过jQuery._data自己调用
	   jQuery._data($("#data")[0],"name","qinliang");
	    jQuery._data($("#data")[0],"sex","male");
       $("#data").click(function()
	   {
	     console.log("1");
	   });
		//获取expando以求获取钥匙
		var expando=jQuery.expando;
		//获取钥匙
		var key=$("#data")[0][expando];
		//获取仓库
		var walhouse=jQuery.cache[key];
		 console.log(walhouse);

note:通过该图我们再次确认了,jQeury内部的数据都是单独保存的,没有放入data域下面进行重新组织,这一点一定要和用户自定义的数据区分开来!
问题12:内部数据和用户数据调用方式如何?

jQuery内部数据通过jQuery._data方法保存

_data: function( elem, name, data ) {
		return internalData( elem, name, data, true );//第四个参数为true表示保存在非data域下面!
	}

用户数据保存在data域下面:

data: function( elem, name, data ) {
		return internalData( elem, name, data );
	}

问题13:我们调用实例方法如果需要设置多个属性和值,那么必须多次调用data方法?

解答:不是的,我们看看实例data方法是如何处理的

<span style="font-size:10px;">if ( typeof key === "object" ) {
			return this.each(function() {
				jQuery.data( this, key );//这说明我们如果要保存多个值,那么可以传入对象字面量
			});
		}</span>

那么我们在看看jQuery.data是如何支持实例方法传入对象字面量的

	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 );
		}
	}

note:jQuery.data支持对象字面量是通过jQuery.extend来实现的,他会把我们通过data实例方法传入的对象字面量全部继承到仓库中!
问题14:如果我们调用data方法不传入参数,或者传入参数是undefined,那是不是说返回的必定是undefined?

解答:不对,我们看看data实例方法是如何处理的

f ( key === undefined ) {
			if ( this.length ) {
				//获取第1个元素的数据
				data = jQuery.data( elem );
				//如果第1个调用元素的parsedAttrs属性为空!
				if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
					i = attrs.length;
					while ( i-- ) {
						// Support: IE11+
						// The attrs elements can be null (#14894)
						if ( attrs[ i ] ) {
							name = attrs[ i ].name;
							if ( name.indexOf( "data-" ) === 0 ) {
								name = jQuery.camelCase( name.slice(5) );
								//通过dataAttr方法获取到HTML5数据
								//传入如dataAttr(elem,"sex",undefined)
								dataAttr( elem, name, data[ name ] );
							}
						}
					}
					jQuery._data( elem, "parsedAttrs", true );
				}
			}
			return data;
		}

note:如果没有传入参数,那么首先获取第一个DOM元素的所有的属性,同时查找该DOM元素上同名的HTML5属性,把这个数据保存到jQuery内部数据中,键名是parsedAttrs!这一点是jQuery智能操作完成的!看下面的例子:

HTML部分:

   <p style="width:100px;height:100px;background-color:red;" id="data" data-sex="male" data-name="qinliang"></p>

JS部分:

  //这时候传入的参数是undefined,所以最后就是把HTML5的数据保存为用户的数据,键名为HTML5键名的
  //缩写版,如"sex"而不是"data-sex"。键值就是HTML5数据的值!
     var result=$("#data").data();
    var result1=$("#data").data("name");
	console.log(result1);//打印qinliang
	 var result2=$("#data").data("sex");
	console.log(result2);//打印male

note:在这里我只想说,如果用户调用data方法时候没有传入任何参数,那么jQuery会把HTML5数据作为用户数据保存,所以下次再次获取数据的时候就可以获取到了!
jQuery是如何把HTML5数据保存为用户数据的呢?

function dataAttr( elem, key, data ) {
	// If nothing was found internally, try to fetch any
	// data from the HTML5 data-* attribute
		//如果传入的data是undefined,同时elemenet是DOM对象,那么我们就获取HTML5上的同名属性!
	if ( data === undefined && elem.nodeType === 1 ) {
		//如果是大写就满足这个正则表达式,那么会添加两个横线并且变成小写!
		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
		data = elem.getAttribute( name );
		if ( typeof data === "string" ) {
			try {
				//如果是true,false,null字符串那么返回非字符串形式的数据,如果不是这几种类型
				data = data === "true" ? true :
					data === "false" ? false :
					data === "null" ? null :
					// Only convert to a number if it doesn&#39;t change the string
				    //如果是数字那么才会转化为数子,如果是JSON类型那么转化为JSON,否则就是原样返回!
					+data + "" === data ? +data :
					rbrace.test( data ) ? jQuery.parseJSON( data ) :
					data;
			} catch( e ) {}
                     //把我们获取到的数据保存为用户数据
	   		// Make sure we set the data so it isn&#39;t changed later
			jQuery.data( elem, key, data );
		} else {
			data = undefined;
		}
	}
	return data;
}

note:我相信你不难看出,最后是通过jQuery.data把数据保存为用户数据的!注意,我们现在回到上面的那个不传入参数的情况,那么他其实是只保存了调用对象的第1个元素的数据作为用户数据,如果有多个DOM元素组成了调用对象,剩余的DOM对象是没有数据的,看下面的例子:

HTML部分

<p style="width:100px;height:100px;background-color:red;" class="data" data-sex="male" data-name="qinliang"></p>
 <p style="width:100px;height:100px;background-color:red;" class="data" id="me"></p>

JS部分:

 //这时候传入的参数是undefined,所以最后就是把HTML5的数据保存为用户的数据,键名为HTML5键名的
  //缩写版,如"sex"而不是"data-sex"。键值就是HTML5数据的值!
     var result=$(".data").data();
    var result1=$(".data").data("name");
	console.log(result1);//打印qinliang
	 var result2=$(".data").data("sex");
	console.log(result2);//打印male
	 var result=$("#me").data();
    var result1=$("#me").data("name");
	console.log(result1);//打印undfined
	 var result2=$("#me").data("sex");
	console.log(result2);//打印undefined

note:虽然第一步$(".data")匹配了多个DOM元素,但是只是把第一个DOM元素的HTML5属性作为第一个DOM元素的内部数据,所以第二个DOM元素,也就是id为me的元素仍然没有name和sex属性值!

问题15:实例data源码中有parsedAttrs,是干嘛用的?

如果我们调用data方法但是没有传入参数,这时候就会存在parsedAttrs了

	jQuery._data( elem, "parsedAttrs", true );//作为jQuery内部数据

其值作为内部数据保存

 //这时候传入的参数是undefined,所以最后就是把HTML5的数据保存为用户的数据,键名为HTML5键名的
  //缩写版,如"sex"而不是"data-sex"。键值就是HTML5数据的值!
     var result=$(".data").data();
     //获取expando以备获取钥匙
	 var expando=jQuery.expando;
	 //获取钥匙
	 var key=$(".data")[0][expando];
	 //获取仓库
	 var walhouse=jQuery.cache;
	 //打开仓库获取数据
	 var result=walhouse[key];
	 console.log(result);

note:通过该图你要知道parseAttrs保存的是true,表示已经解析过HTML5属性了;但是注意:内部数据和外部数据虽然获取的方式是一样的,都是获取expando,获取钥匙,获取仓库,获取数据。但是你应该马上反应过来,上面的parseAttrs没有保存到data域下面,这就是他通过内部数据保存的结果。同时,你也应该看到内部数据和用户自定义数据在这个图上存在的共存的情况!

问题16:data如何体现了获取数据的逻辑?

	return arguments.length > 1 ?
			// Sets one value
			this.each(function() {
				jQuery.data( this, key, value );
			}) :
			// Gets one value
			// Try to fetch any internally stored data first
			//如果传入的参数不大于1,也就是传入单个值,因为不传值上面已经return了
			//那么用dataAttr获取值,传入参数为第一个DOM对象,第二个参数是data方法传入的参数
			//第三个参数是第一个DOM对象的所有通过$.data保存的数据
			elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
	}

note:jQuery.data(elem,key)就是获取元素上指定键名的键值数据,如果键值存在不是undefined那么dataAttr不做任何处理,直接返回;如果键值不存在那么dataAttr就回去获取HTML5属性值,保存为用户数据的同时返回数据!所以下面这种情况是有值返回的。
  HTML部分:

   <p style="width:100px;height:100px;background-color:red;" id="data" data-name="qinliang"></p>

JS部分:

   var result=$("#data").data("name");
   console.log(result);

note:用户没有保存数据的情况下我们却获取到了数据,这就是dataAttr的功劳,他把数据保存为用户数据的同时把数据返回。
问题17:除了Object,DOM,还有没有其它对象可以用来保存数据?

  看看筛选函数

if ( !jQuery.acceptData( elem ) ) {
		return;
	}

详细代码如下

noData: {
		"applet ": true,
		"embed ": true,
		// ...but Flash objects (which have this classid) *can* handle expandos
		"object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
	}
jQuery.acceptData = function( elem ) {
	var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
		nodeType = +elem.nodeType || 1;
	// Do not set data on non-element DOM nodes because it will not be cleared (#8335).
	//如果元素不是Element同时也不是document那么直接返回false表示不能用来保存数据!
	return nodeType !== 1 && nodeType !== 9 ?
		false :
        //如果是元素或者为document对象可以保存数据;applet和embed不能保存数据;Flash可以保存数据!
		// Nodes accept data unless otherwise specified; rejection can be conditional
		!noData || noData !== true && elem.getAttribute("classid") === noData;
};

note:Element对象,document对象,Flash对象可以保存数据,applet和embed不能保存数据!很显然JS对象是可以保存数据的,因为里面没有针对JS对象排除的代码!
问题18:如何判断一个元素是否有自己的数据?

hasData: function( elem ) {
		//如果是DOM对象,那么就是判断仓库是否为空的,不需要特别针对data域,elem[jQuery.expando]
		//是钥匙,jQuery.cache是仓库。如果是JS对象等其它对象,那么钥匙就是jQuery.expando,仓库就是自身!
		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
		//仓库非空,通过isEmptyObject来判断
		return !!elem && !isEmptyDataObject( elem );
	}

详细见isEmptyDataObject

function isEmptyDataObject( obj ) {
	var name;
	for ( name in obj ) {
		// if the public data object is empty, the private is still empty
		//如果data域是空的,那么继续判断下一个字段
		if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
			continue;
		}
		//如果有一个除了toJSON的字段,那么表示非空!
		if ( name !== "toJSON" ) {
			return false;
		}
	}
	return true;
}

note:如果有一个除了toJSON的字段,那么表示这个数据对象不是空对象!
有了上面的18个问题,看jQuery.data或者jQuery._data的源码,或者实例data方法的源码应该不在话下了!源码如下:

jQuery.data方法源码

data: function( elem, name, data ) {
		return internalData( elem, name, data );
	}

jQuery._data方法源码

_data: function( elem, name, data ) {
		return internalData( elem, name, data, true );
	}

实例data方法源码

	data: function( key, value ) {
		var i, name, data,
			//获取第1个调用元素
			elem = this[0],
			//保存第一个调用元素的属性集合!
			attrs = elem && elem.attributes;
		// Special expections of .data basically thwart jQuery.access,
		// so implement the relevant behavior ourselves
		// Gets all values
		//没有传入key或者key为undefined
		if ( key === undefined ) {
			if ( this.length ) {
				//获取第1个元素的数据
				data = jQuery.data( elem );
				//如果第1个调用元素的parsedAttrs属性为空!
				if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
					i = attrs.length;
					while ( i-- ) {
						// Support: IE11+
						// The attrs elements can be null (#14894)
						if ( attrs[ i ] ) {
							name = attrs[ i ].name;
							if ( name.indexOf( "data-" ) === 0 ) {
								name = jQuery.camelCase( name.slice(5) );
								//通过dataAttr方法获取到HTML5数据
								//传入如dataAttr(elem,"sex",undefined)
								dataAttr( elem, name, data[ name ] );
							}
						}
					}
					jQuery._data( elem, "parsedAttrs", true );
				}
			}
			return data;
		}
		// Sets multiple values
		if ( typeof key === "object" ) {
			return this.each(function() {
				jQuery.data( this, key );
			});
		}
		return arguments.length > 1 ?

			// Sets one value
			this.each(function() {
				jQuery.data( this, key, value );
			}) :

			// Gets one value
			// Try to fetch any internally stored data first
			elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
	}

internalRemoveData源码:

function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
	if ( !jQuery.acceptData( elem ) ) {
		return;
	}
	var ret, thisCache,
		internalKey = jQuery.expando,
		// We have to handle DOM nodes and JS objects differently because IE6-7
		// can't GC object references properly across the DOM-JS boundary
		isNode = elem.nodeType,
		// Only DOM nodes need the global jQuery cache; JS object data is
		// attached directly to the object so GC can occur automatically
		cache = isNode ? jQuery.cache : elem,
		// Only defining an ID for JS objects if its cache already exists allows
		// the code to shortcut on the same path as a DOM node with no cache
		id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
	// 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] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
		return;
	}
	if ( !id ) {
		// Only DOM nodes need a new unique ID for each element since their data
		// ends up in the global cache
		if ( isNode ) {
			id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
		} else {
			id = internalKey;
		}
	}
	if ( !cache[ id ] ) {
		// Avoid exposing jQuery metadata on plain JS objects when the object
		// is serialized using JSON.stringify
		cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
	}
	// An object can be passed to jQuery.data instead of a key/value pair; this gets
	// shallow copied over onto the existing cache
	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 );
		}
	}
	thisCache = cache[ id ];
	// jQuery data() is stored in a separate object inside the object's internal data
	// cache in order to avoid key collisions between internal data and user-defined
	// data.
	if ( !pvt ) {
		if ( !thisCache.data ) {
			thisCache.data = {};
		}
		thisCache = thisCache.data;
	}
	if ( data !== undefined ) {
		thisCache[ jQuery.camelCase( name ) ] = data;
	}
	// Check for both converted-to-camel and non-converted data property names
	// If a data property was specified
	if ( typeof name === "string" ) {
		// First Try to find as-is property data
		ret = thisCache[ name ];
		// Test for null|undefined property data
		if ( ret == null ) {
			// Try to find the camelCased property
			ret = thisCache[ jQuery.camelCase( name ) ];
		}
	} else {
		ret = thisCache;
	}

	return ret;
}

总结:

对于jQuery.data保存数据和获取数据严格遵守下面的次序:

第一步:获取expando以备用他来获取钥匙。expando=jQuery.expando;

第二步:通过expando获取到钥匙。JS对象:key=expando; DOM对象key=elem[expando]
第三步:获取仓库。JS对象walhouse=elem;DOM对象walhouse=jQuery.cache

第四步:用钥匙打开仓库。JS对象data=elem[expando],DOM对象data=walhouse[key]

第五步:获取数据,如果是用户数据要在data的data域下面,如果是内部数据不用到data域下面!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn