>  기사  >  웹 프론트엔드  >  jQuery.data, jQuery._data, 데이터 인스턴스 함수의 사용법과 주의사항에 대한 심층 분석

jQuery.data, jQuery._data, 데이터 인스턴스 함수의 사용법과 주의사항에 대한 심층 분석

巴扎黑
巴扎黑원래의
2017-06-20 10:06:331701검색

질문 1: jQuery에 저장되는 데이터 형식은 무엇인가요? 데이터를 통해 저장되는 데이터와 등록된 이벤트 형식의 차이점은 무엇인가요?

먼저 다음 코드를 살펴보세요.

    $._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: 이 그림을 보면 알 수 있습니다. through _data 저장된 데이터는 $._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);

참고: 이 그림을 통해 사용자가 저장한 데이터를 확인할 수 있습니다. 데이터 방식으로 저장된 데이터는 커스텀 데이터만 저장되지만 이벤트 등록 등 내부 데이터는 사용자 데이터 범위에 포함되지 않습니다.
질문 3: 해당 데이터는 jQuery 내부 데이터이며 해당 데이터는 사용자- 정의된 데이터 ?

답변: 예를 들어 이벤트 등록이나 _data는 jQuery를 통해 내부적으로 호출됩니다. 저장된 데이터 형식은 첫 번째 그림이고, 사용자가 데이터를 통해 저장한 데이터는 두 번째 그림 형식뿐입니다. 사용자 정의 데이터가 포함되어 있습니다!

질문 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);

참고: 이 그림에서 우리는 인스턴스 객체의 하단에 저장된 데이터 형식에 세 개의 필드가 있음을 알 수 있습니다. 데이터 필드는 사용자의 데이터를 저장합니다. 핸들러 필드는 범용입니다. 콜백 함수 !
질문 5: jQuery.expando는 도대체 무엇인가요?

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

데이터를 저장할 때마다 난수를 생성하나요? 사실 아니요, 처음 호출할 때 한 번만 생성합니다.

다음 코드는 동일한 난수를 생성합니다.

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

참고: 모든 DOM은 데이터를 저장하기 위해 동일한 확장을 사용합니다. 즉, 각 DOM에는 동일한 속성 이름인 jQuery.expando가 있습니다!

질문 5: Expando가 고유한데 어떻게 각 DOM이 다른 키를 가질 수 있습니까?

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

참고: 이 단락 코드는 속성 이름은 동일하고 속성 값은 다르며 jQuery.guid를 통해 고유성이 보장됩니다.

질문 6: jQuery.guid는 무엇입니까? 각 DOM 요소에 고유한 키가 있는지 확인하는 이유는 무엇입니까?

프록시 함수가 새 함수를 생성하면 guid를 처리하고 해당 값을 증가시킵니다. jQuery.event.add 메서드를 사용하면 guid 값이 없는 경우 각 바인딩된 함수에 대해 새 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;
	}

함수의 인스턴스에서 함수가 한 번만 호출되는 경우 guid 값을 설정합니다( 실제로 프록시 기능)

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

인스턴스가 데이터를 저장할 때 각 DOM 객체의 동일한 속성, 즉 jQuery.expando 속성에 대해 고유한 키 값을 설정합니다:

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

note:j

Query.guid 이벤트 바인딩 및 데이터 저장에 사용되며, 저장된 각 데이터의 DOM과 바인딩된 각 이벤트의 콜백 함수에 고유한 guid 값을 할당합니다!

질문 7: 키를 얻었는데 창고는 어디에 있나요?

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

여기서 우리는 그것이 DOM 객체라면 웨어하우스는 jQuery.cache이고, js 객체라면 웨어하우스 자체라는 것을 알 수 있습니다!
질문 8: 키를 얻었고, 웨어하우스도 사용할 수 있으며, 데이터를 얻을 수 있다면 내 데이터는 어디에 저장되나요?

위에서 말했듯이: 인스턴스 개체의 하단에 저장된 데이터 형식에는
세 개의 필드가 있으며, 데이터 필드는 사용자의 데이터를 저장합니다. field는 universal입니다. 콜백 함수입니다!

내 데이터는 어떻게 데이터 필드에 저장되나요?

jQuery.cache={},
cache = isNode ? jQuery.cache : elem,
참고: 사용자 데이터는 웨어하우스의 데이터 필드에 저장됩니다. .새로 생성할 필요는 없습니다!
질문 9: 데이터를 얻을지 저장할지 어떻게 판단하나요?

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

참고: 데이터가 존재하면 데이터를 저장한다는 의미입니다. 특정 도메인. 사용자 데이터는 창고의 데이터 필드 아래에 있고 내부 데이터는 창고에 직접 있습니다! 데이터를 얻으려면 이름이 문자열이면 창고에서 특정 콘텐츠를 가져오고 그렇지 않으면 직접 가져옵니다.
질문 10:

Object 개체에 액세스할 수 있습니까?

위의 데이터를 저장합니까?

     //获取到数据仓库,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;
참고: 이 데이터 저장 방법은 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, 데이터 인스턴스 함수의 사용법과 주의사항에 대한 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.