博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jQuery剥皮三- data、proxy、event
阅读量:5750 次
发布时间:2019-06-18

本文共 5194 字,大约阅读时间需要 17 分钟。

  hot3.png

jquery1.4  

这里使用了 jQuery1.4,为什么使用 1.4 因为 1.4 很多特性没有添加分析起来相对容易。

这个 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。如下图:

214745_48tr_568138.png

现在来看一张图,来观察 data 实现的方法

220447_3JyN_568138.png

实现方法就是 jQuery 在对元素操作的时候会赋值一个 "jQuery" + now() 时间戳的属性,其值是一个 uuid 唯一的数字,每次操作会加 1 ,然后在 jQuery 的 cache 的对象静态变量中根据这个 uuid 赋值一个 key 就像这样 {5:{}}。并且把你要加入的 data 放去这个 key 为 5 的对象中 {5:{tudou:"abc"}}。他们唯一关联的就是这个 uuid 。

看看 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 方法去实现值的设置或者获取 

之前简单的  原理差不多是这样

proxy 比较简单,但是很容易晕的一个东西,给你来几个 proxy + 返回闭包 基本都会晕 :(

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

转载于:https://my.oschina.net/itudou/blog/346113

你可能感兴趣的文章
Linux的netstat命令使用
查看>>
大快网站:如何选择正确的hadoop版本
查看>>
经过这5大阶段,你离Java程序员就不远了!
查看>>
IntelliJ IDEA 连接数据库详细过程
查看>>
PHP-X开发扩展
查看>>
android学习笔记——onSaveInstanceState的使用
查看>>
工作中如何做好技术积累
查看>>
怎么用sysLinux做U盘双PE+DOS??
查看>>
Spring Transactional
查看>>
shell脚本实例
查看>>
我的友情链接
查看>>
Windows Phone 7 隔离存储空间资源管理器
查看>>
apache安装报错undefined reference ssl
查看>>
关于爱情只有一句忠告
查看>>
CentOS 7下安装部署Oracle11g图文教程
查看>>
F#初学笔记06
查看>>
实战:将企业域名解析委派给企业DNS服务器
查看>>
在Lync 2013环境部署Office Web Apps
查看>>
微软大会Ignite,你准备好了么?
查看>>
读书笔记-高标管事 低调管人
查看>>