jQuery剝皮三- data、proxy、event

jquery1.4  jquery1.4下載node

這裏使用了 jQuery1.4,爲何使用 1.4 由於 1.4 不少特性沒有添加分析起來相對容易。jquery


這個 data 的實現是擴展在 jQuery 靜態函數裏面的,咱們日常這樣( $('#data').data('tudou', 'abc') )調用的是 jQuery 原型上的 data ,原型上面的 data 再調用下面 jQuery 靜態的 data 方法實現。數組

jQuery.extend({
	cache: {},
	
	expando:expando,

	// The following elements throw uncatchable exceptions if you
	// attempt to add expando properties to them.
	noData: {
		"embed": true,
		"object": true,
		"applet": true
	},

	data: function( elem, name, data ) {
        // 不是正確的元素過濾掉
		if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
			return;
		}

		elem = elem == window ?
			windowData :
			elem;

		var id = elem[ expando ], cache = jQuery.cache, thisCache;

		// Handle the case where there's no name immediately
        // 沒有 data 名 且 也沒有設置過 data 返回
		if ( !name && !id ) {
			return null;
		}

		// Compute a unique ID for the element
		if ( !id ) { 
			id = ++uuid;
		}

		// Avoid generating a new cache unless none exists and we
		// want to manipulate it.
		if ( typeof name === "object" ) {
			elem[ expando ] = id;
            // 若是傳遞過來的是對象,直接擴展到 cache 對象中
			thisCache = cache[ id ] = jQuery.extend(true, {}, name);
		} else if ( cache[ id ] ) {
            // 若是有存儲過,則拿到之前的
			thisCache = cache[ id ];
		} else if ( typeof data === "undefined" ) {
			thisCache = emptyObject;
		} else {
		        // 第一次存儲,要新建一個空對象
			thisCache = cache[ id ] = {};
		}

		// Prevent overriding the named cache with undefined values
        // 把數據寫入 cache 存儲 根據uuid
		if ( data !== undefined ) {
			elem[ expando ] = id;
			thisCache[ name ] = data;
		}
        // 返回附加的數據
		return typeof name === "string" ? thisCache[ name ] : thisCache;
	},

	removeData: function( elem, name ) {
		if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
			return;
		}

		elem = elem == window ?
			windowData :
			elem;

		var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];

		// If we want to remove a specific section of the element's data
		if ( name ) {
			if ( thisCache ) {
				// Remove the section of cache data
				delete thisCache[ name ];

				// If we've removed all the data, remove the element's cache
				if ( jQuery.isEmptyObject(thisCache) ) {
					jQuery.removeData( elem );
				}
			}

		// Otherwise, we want to remove all of the element's data
		} else {
			// Clean up the element expando
			try {
				delete elem[ expando ];
			} catch( e ) {
				// IE has trouble directly removing the expando
				// but it's ok with using removeAttribute
				if ( elem.removeAttribute ) {
					elem.removeAttribute( expando );
				}
			}

			// Completely remove the data cache
			delete cache[ id ];
		}
	}
});


這個 data 的實現是在 jQuery 函數上建立了一個靜態變量 cache 對象,key 就是 data 的 name, value 就是 data 的 value。以下圖:閉包

如今來看一張圖,來觀察 data 實現的方法app

實現方法就是 jQuery 在對元素操做的時候會賦值一個 "jQuery" + now() 時間戳的屬性,其值是一個 uuid 惟一的數字,每次操做會加 1 ,而後在 jQuery 的 cache 的對象靜態變量中根據這個 uuid 賦值一個 key 就像這樣 {5:{}}。而且把你要加入的 data 放去這個 key 爲 5 的對象中 {5:{tudou:"abc"}}。他們惟一關聯的就是這個 uuid 。less

看看 jQuery 的原型實現函數

jQuery.fn.extend({
	data: function( key, value ) {
		if ( typeof key === "undefined" && this.length ) {
			return jQuery.data( this[0] );
		} else if ( typeof key === "object" ) {
            // 對象直接進行 data 存儲
			return this.each(function() {
				jQuery.data( this, key );
			});
		}
		var parts = key.split(".");
		parts[1] = parts[1] ? "." + parts[1] : "";
        // 若是隻傳 name 就是獲取值
		if ( value === undefined ) {
            // 設置會觸發 getData 自定義方法 他們均可以經過 bind 捕獲
			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

			if ( data === undefined && this.length ) {
				data = jQuery.data( this[0], key );
			}
			return data === undefined && parts[1] ?
				this.data( parts[0] ) :
				data;
		} else {
            // 設置值會觸發 setData 方法   他們均可以經過 bind 捕獲
			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() {
				jQuery.data( this, key, value );
			});
		}
	},

	removeData: function( key ) {
		return this.each(function() {
			jQuery.removeData( this, key );
		});
	}
});

這裏的實現就顯得輕鬆許多了,只須要多 參數、獲取/設置 值進行處理就能夠了 ,而後去調用對應的 jQuery.data 方法去實現值的設置或者獲取 ui

以前簡單的模擬過一個  原理差很少是這樣this

proxy 比較簡單,可是很容易暈的一個東西,給你來幾個 proxy + 返回閉包 基本都會暈 :(spa

proxy: function( fn, proxy, thisObject ) {
		if ( arguments.length === 2 ) {
			if ( typeof proxy === "string" ) { // 第一種方式調用方式 $.proxy(obj, 'fn')
				thisObject = fn;
				fn = thisObject[ proxy ];
				proxy = undefined;
			} else if ( proxy && !jQuery.isFunction( proxy ) ) { // 第二種調用方式 $.proxy(obj.fn, obj)
				thisObject = proxy;
				proxy = undefined;
			}
		}

		if ( !proxy && fn ) {
            /*
            * 返回重構好 this 的函數, 那麼這裏的 thisObject 是指向了最終 this 要指向的地方
            */
			proxy = function() {
				return fn.apply( thisObject || this, arguments );
			};
		}

		// Set the guid of unique handler to the same of original handler, so it can be removed
		if ( fn ) {
			proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
		}

		// So proxy can be declared as an argument
		return proxy;
	}

值得關注的就是 這個 thisObject 由於 js 中 函數、對象、數組是傳址的,因此 thisObject 能指向你要代理到那個對象的 this 中。感受很是繞,可是搞明白也就沒啥了。隨便說下 thisObject 確定是一個閉包了

var obj = {
          name: 'tudousi',
          test: function() {
            alert( this.name );
            return false;
          }
        };
        var func = $.proxy(obj, 'test');
        $('.show').click(func);
相關文章
相關標籤/搜索