首頁 web前端 js教程 深入解析jQuery.data,jQuery._data以及data實例函數的用法及注意事項

深入解析jQuery.data,jQuery._data以及data實例函數的用法及注意事項

Jun 20, 2017 am 10:06 AM
jquery 分析 深入 原始碼 理解

問題1:jQuery內部的資料保存的格式是什麼,透過data保存的資料和註冊的事件格式有什麼區別?

首先看下面的程式碼:

    $._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);
登入後複製

note :透過該圖片我們知道,透過_data儲存的資料是儲存在DOM物件上面的,透過$._data(document.getElementById("data"))取得到的物件透過鍵名就可以存取;但對於事件綁定的函數,只能透過$._data(document.getElementById("data")).events["click"]才能存取。

問題2:使用者透過$.data儲存的資料格式是如何的?

我們修改上面的程式碼為:

 $.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);
登入後複製

note:透過該圖,你會發現用戶保存的數據,也就是透過$.data方法保存的數據只會保存自訂數據,而像事件註冊等屬於內部的數據,這部分數據不在用戶數據範圍之內!
問題3:那些數據是jQuery內部數據,那些數據是用戶自訂數據?

 解答:像事件event註冊或_data是透過jQuery內部調用的,保存的數據格式就是第一張圖,而使用者透過data保存的資料是第二張圖的格式,這種格式只包含使用者自訂的資料!

#問題4:我們在jQuery實例上綁定的數據在底層是如何保存的?和透過jQuery保存資料格式是否一樣?

我們把上面的例子修改為實例方法:

 $("#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);
登入後複製

note:透過該圖我們知道,實例物件底層保存的資料格式具有三個域,分別為data域保存使用者的資料;events保存的是物件的事件;handler域就是通用的回呼函數!
問題5:jQuery.expando是什麼鬼?

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

每次儲存資料的時候都會產生隨機數?其實不是的,他只會在第一次呼叫的時候產生一次,這一點一定要注意,所以不管你呼叫多少次data方法,其值都是一樣的!

下面的程式碼,產生的隨機數都是一樣的.

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

note:所有的DOM都是以相同的expando來保存資料的,也就是每一個DOM都有相同的屬性名jQuery.expando!

問題5:既然expando是唯一的,那麼怎麼使得每一個DOM都有不同的鑰匙?

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

note:這一段程式碼告訴我們,雖然屬性名稱是相同的,但是屬性值是不一樣的,而且是透過jQuery.guid來保證唯一性的。

問題6:jQuery.guid是什麼鬼?他為啥能夠保證每一個DOM元素具有不重複的鑰匙?
proxy函數產生新的函數的時候會處理guid,讓他的值遞增:

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;
	}
登入後複製

jQuery.event.add方法中,對每一個綁定的函數都會設定一個新的guid,前提是他沒有guid值:

if ( !handler.guid ) {//没有guid值添加
	handler.guid = jQuery.guid++;
}
登入後複製

在實例在on函數中,如果一個函數只會被呼叫一次,那麼設定guid值(其實就是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保证唯一!
		}
登入後複製

實例儲存資料的時候,為每個DOM物件的相同的屬性,即jQuery.expando屬性設定一個唯一的鑰匙值:

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

note:jQuery.guid的作用是用於事件綁定中和資料保存中,為每一個保存的資料的DOM和每一個綁定事件的回調函數分配一個唯一的guid值!
問題7:鑰匙獲取到了,那麼倉庫在那裡?

jQuery.cache={},
cache = isNode ? jQuery.cache : elem,
登入後複製

從這裡我們知道,如果是DOM對象,那麼倉庫就是jQuery.cache,如果是js對像那麼倉庫就是自身!
問題8:鑰匙獲取到了,倉庫也有了,可以獲取到數據了,那麼我的數據是保存在那裡的?

上面我們說過:實例物件底層保存的資料格式具有三個域,分別為data域保存使用者的資料;events保存的是物件的事件;handler域就是通用的回呼函數!那麼我的資料是如何保存到data域下面的:

	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域下面!
		}
	}
登入後複製

note:用戶資料保存在倉庫的data域下面,如果是jQuery資料保存在倉庫裡就可以了,不用重新開啟一個空間!
問題9:如何判斷是獲取數據還是保存數據?

     //获取到数据仓库,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;
登入後複製

note:如果data存在,表示是保存數據,這時候把數據保存到特定的域下面。使用者資料在倉庫的data網域下面,內部資料直接在倉庫裡面!;如果是取得數據,如果name是string那麼取得倉庫中特定的內容,否則直接傳回倉庫本身!
問題10:是否可以在Object物件上面儲存資料?

          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
登入後複製

note:這種儲存資料的方式不是DOM觸發的,而是JS物件完成的。然而data方法屬於jQuery對象,所以無法直接呼叫data方法,但是可以呼叫jQuery.data方法!這種方式也可以在Object對像上面保存資料!我們來看看這種方式保存資料格式是怎麼樣的:

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

以上是深入解析jQuery.data,jQuery._data以及data實例函數的用法及注意事項的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

jQuery小技巧:快速修改頁面所有a標籤的文本 jQuery小技巧:快速修改頁面所有a標籤的文本 Feb 28, 2024 pm 09:06 PM

標題:jQuery小技巧:快速修改頁面所有a標籤的文字在網頁開發中,我們經常需要對頁面中的元素進行修改和操作。使用jQuery時,有時候需要一次修改頁面中所有a標籤的文字內容,這樣可以節省時間和精力。以下將介紹如何使用jQuery快速修改頁面所有a標籤的文本,同時給出具體的程式碼範例。首先,我們需要引入jQuery庫文件,確保在頁面中引入了以下程式碼:&lt

PHP程式碼在瀏覽器中如何顯示原始碼而不被解釋執行? PHP程式碼在瀏覽器中如何顯示原始碼而不被解釋執行? Mar 11, 2024 am 10:54 AM

PHP程式碼在瀏覽器中如何顯示原始碼而不被解釋執行? PHP是一種伺服器端腳本語言,通常用於開發動態網頁。當PHP檔案在伺服器上被要求時,伺服器會解釋執行其中的PHP程式碼,並將最終的HTML內容傳送到瀏覽器以供顯示。然而,有時我們希望在瀏覽器中直接展示PHP檔案的原始碼,而不是被執行。本文將介紹如何在瀏覽器中顯示PHP程式碼的源碼,而不被解釋執行。在PHP中,可以使

織夢CMS二級目錄打不開的原因分析 織夢CMS二級目錄打不開的原因分析 Mar 13, 2024 pm 06:24 PM

標題:解析織夢CMS二級目錄打不開的原因及解決方案織夢CMS(DedeCMS)是一款功能強大的開源內容管理系統,被廣泛應用於各類網站建設中。然而,有時在搭建網站過程中可能會遇到二級目錄無法開啟的情況,這給網站的正常運作帶來了困擾。在本文中,我們將分析二級目錄打不開的可能原因,並提供具體的程式碼範例來解決這個問題。一、可能的原因分析:偽靜態規則配置問題:在使用

如何判斷jQuery元素是否具有特定屬性? 如何判斷jQuery元素是否具有特定屬性? Feb 29, 2024 am 09:03 AM

如何判斷jQuery元素是否具有特定屬性?在使用jQuery操作DOM元素時,常會遇到需要判斷元素是否具有某個特定屬性的情況。在這種情況下,我們可以藉助jQuery提供的方法來輕鬆實現這項功能。以下將介紹兩種常用的方法來判斷一個jQuery元素是否具有特定屬性,並附上具體的程式碼範例。方法一:使用attr()方法和typeof運算子//判斷元素是否具有特定屬

分析騰訊主要的程式語言是否為Go 分析騰訊主要的程式語言是否為Go Mar 27, 2024 pm 04:21 PM

標題:騰訊主要的程式語言是否為Go:一項深入分析騰訊作為中國領先的科技公司,在程式語言的選擇上一直備受關注。近年來,有人認為騰訊主要採用Go作為主要的程式語言。本文將對騰訊主要的程式語言是否為Go進行深入分析,並給出具體的程式碼範例來支持這一觀點。一、Go語言在騰訊的應用Go是一種由Google開發的開源程式語言,它的高效性、並發性和簡潔性受到眾多開發者的喜

golang框架原始碼學習與應用全面指南 golang框架原始碼學習與應用全面指南 Jun 01, 2024 pm 10:31 PM

透過理解Golang框架原始碼,開發者可以掌握語言精髓和擴展框架功能。首先,取得原始碼並熟悉其目錄結構。其次,閱讀程式碼、追蹤執行流程和理解依賴關係。實戰案例展示如何應用這些知識:建立自訂中間件並擴展路由系統。最佳實踐包括逐步學習、避免盲目複製貼上、利用工具和參考線上資源。

PHP原始碼錯誤:解決index報錯問題 PHP原始碼錯誤:解決index報錯問題 Mar 10, 2024 am 11:12 AM

PHP原始碼錯誤:解決index報錯問題,需要具體程式碼範例隨著互聯網的快速發展,開發人員在編寫網站和應用程式時經常會遇到各種各樣的問題。其中,PHP作為一種流行的伺服器端腳本語言,其原始碼錯誤是開發者經常遇到的一個問題之一。有時候,當我們嘗試開啟網站的index頁面時,會出現各種不同的錯誤訊息,例如"InternalServerError"、"Unde

使用jQuery為表格新增一行的方法介紹 使用jQuery為表格新增一行的方法介紹 Feb 29, 2024 am 08:12 AM

jQuery是一個受歡迎的JavaScript函式庫,廣泛用於網頁開發。在網頁開發過程中,經常需要透過JavaScript動態地在表格中新增一行。本文將介紹如何使用jQuery為表格新增一行,並提供具體的程式碼範例。首先,我們需要在HTML頁面中引入jQuery函式庫。可以透過以下程式碼在標籤中引入jQuery庫:

See all articles