Heim  >  Artikel  >  Web-Frontend  >  Eingehende Analyse der Verwendung und Vorsichtsmaßnahmen von jQuery.data, jQuery._data und Dateninstanzfunktionen

Eingehende Analyse der Verwendung und Vorsichtsmaßnahmen von jQuery.data, jQuery._data und Dateninstanzfunktionen

巴扎黑
巴扎黑Original
2017-06-20 10:06:331755Durchsuche

Frage 1: Welches Format haben die in jQuery gespeicherten Daten? Was ist der Unterschied zwischen den durch Daten gespeicherten Daten und dem registrierten Ereignisformat?

Sehen Sie sich zunächst den folgenden Code an:

    $._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);

Hinweis: Aus diesem Bild wissen wir, dass die über _data gespeicherten Daten im DOM-Objekt gespeichert sind. Auf das über $._data(document.getElementById("data")) erhaltene Objekt kann über zugegriffen werden Schlüsselname. to; aber für ereignisgebundene Funktionen kann nur über $._data(document.getElementById("data")).events["click"] zugegriffen werden.

Frage 2: Welches Format haben die vom Benutzer über $.data gespeicherten Daten?

Wir ändern den obigen Code in:

 $.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);
Hinweis: Bestanden In diesem Bild werden Sie feststellen, dass die vom Benutzer gespeicherten Daten, also die über die $.data-Methode gespeicherten Daten, nur benutzerdefinierte Daten speichern, während interne Daten wie die Ereignisregistrierung nicht in den Geltungsbereich fallen Benutzerdaten!

Frage 3: Welche Daten sind jQuery-interne Daten und welche Daten sind benutzerdefinierte Daten?

Antwort: Die Ereignisregistrierung oder _data wird intern über jQuery aufgerufen und das gespeicherte Datenformat ist das Das erste Bild und die vom Benutzer gespeicherten Daten haben das Format des zweiten Bildes. Dieses Format enthält nur benutzerdefinierte Daten!

Frage 4: Wir binden an die jQuery

Instanz Wie werden die Daten auf der untersten Ebene gespeichert?

Wir ändern das obige Beispiel in eine Instanzmethode:

 $("#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);
Hinweis: Wir Aus diesem Bild wissen Sie, dass das am unteren Rand des Instanzobjekts gespeicherte Datenformat drei Felder enthält. Das Datenfeld speichert die Datenereignisse des Benutzers. Das Handlerfeld ist die allgemeine Rückruffunktion >!

Frage 5: Was zum Teufel ist jQuery.expando? Wird bei jedem Speichern der Daten eine Zufallszahl generiert? Nein, das wird nur der Fall sein Dies muss beim ersten Aufruf einmal generiert werden. Unabhängig davon, wie oft Sie die Datenmethode aufrufen, ist der Wert derselbe!

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

Hinweis: Alle DOMs verwenden dasselbe Expando zum Speichern von Daten,

das heißt, jedes DOM hat den gleichen Attributnamen jQuery.expando

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

Frage 5: Da expando einzigartig ist, wie stellen Sie sicher, dass jedes DOM einen anderen Schlüssel hat?

Hinweis: Dieser Code sagt uns, dass
obwohl der Attributname der ist Das Gleiche gilt, der Attributwert ist unterschiedlich und die Einzigartigkeit wird durch jQuery.guid garantiert.

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

Frage 6: Was ist jQuery.guid? Warum kann es sicherstellen, dass jedes DOM-Element einen eindeutigen Schlüssel hat? Die Proxy-Funktion verarbeitet die GUID, also ihren Wert wird inkrementiert:

In der jQuery.event.add-Methode wird für jede gebundene Funktion eine neue Guid festgelegt, sofern sie keinen Guid-Wert hat:

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;
	}
In Wenn eine Funktion nur einmal aufgerufen wird, legen Sie den GUID-Wert (eigentlich die Proxy-Funktion) fest.

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

Wenn die Instanz Daten speichert, gilt für jedes DOM-Objekt das gleiche Attribut Das heißt, das jQuery.expando-Attribut legt einen eindeutigen Schlüsselwert fest:

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保证唯一!
		}
Hinweis: j

Query.guid wird für die Ereignisbindung und Datenspeicherung verwendet, für jedes DOM gespeicherter Daten und jedes Der Rückruffunktion eines gebundenen Ereignisses wird ein eindeutiger Guid-Wert zugewiesen!

if ( isNode ) {
		id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
		} else {
			id = internalKey;
		}
Frage 7: Der Schlüssel wird erhalten, also wo ist das Lager?


Von hier aus wissen wir das Wenn es sich um ein DOM-Objekt handelt, ist das Warehouse jQuery.cache. Wenn es ein js-Objekt ist, ist es das Warehouse selbst.
Frage 8: Der Schlüssel wird abgerufen, das Warehouse ist ebenfalls verfügbar und die Daten können verfügbar sein erhalten, wo werden meine Daten gespeichert?

jQuery.cache={},
cache = isNode ? jQuery.cache : elem,
Wie wir oben gesagt haben: Das am Ende des Instanzobjekts gespeicherte Datenformat hat jeweils

drei Felder, das Datenfeld speichert die Daten des Benutzers Das Datenereignis des Objekts; das Handlerfeld ist eine allgemeine Rückruffunktion!
Wie werden meine Daten unter dem Datenfeld gespeichert:

Hinweis: Benutzerdaten werden unter dem Datenfeld gespeichert des Lagers. Wenn die jQuery-Daten im Lager gespeichert sind, muss kein neuer Speicherplatz geöffnet werden!
Frage 9: Wie kann ich beurteilen, ob Daten abgerufen oder gespeichert werden sollen?

	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域下面!
		}
	}

Hinweis: Wenn Daten vorhanden sind, bedeutet dies: Speichern Sie die Daten. Speichern Sie die Daten zu diesem Zeitpunkt in einer bestimmten Domäne. Die Benutzerdaten befinden sich in der Datendomäne des Lagers, und die internen Daten befinden sich direkt im Lager! Wenn es sich um Daten handelt und der Name eine Zeichenfolge ist, wird der spezifische Inhalt im Lager abgerufen, andernfalls wird er direkt abgerufen Zurück zum Lager selbst!
Frage 10: Ist es möglich, dass in

Objekt
     //获取到数据仓库,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;
Daten darauf gespeichert werden


Hinweis: Diese Art der Datenspeicherung wird nicht durch DOM ausgelöst, aber durch JS-Objekt. Die Datenmethode gehört jedoch zum jQuery-Objekt , daher kann die Datenmethode nicht direkt aufgerufen werden

, aber die Methode jQuery.data kann auch Daten auf dem Objektobjekt speichern! Ein Blick auf das so gespeicherte Datenformat:
          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
 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域下面!

Das obige ist der detaillierte Inhalt vonEingehende Analyse der Verwendung und Vorsichtsmaßnahmen von jQuery.data, jQuery._data und Dateninstanzfunktionen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn