文档章节

jQuery剥皮三- data、proxy、event

开源中国最帅没有之一
 开源中国最帅没有之一
发布于 2014/11/18 22:13
字数 1084
阅读 295
收藏 17

jquery1.4  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。如下图:

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

实现方法就是 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);



© 著作权归作者所有

上一篇: 阅读连接
开源中国最帅没有之一

开源中国最帅没有之一

粉丝 41
博文 22
码字总数 14155
作品 5
成都
程序员
私信 提问
加载中

评论(4)

开源中国最帅没有之一
开源中国最帅没有之一

引用来自“开源中国董事会主席”的评论

1.4 都是多少年前的版本了40

哈哈 学习嘛 13
开源中国董事会主席
开源中国董事会主席
1.4 都是多少年前的版本了40
开源中国最帅没有之一
开源中国最帅没有之一

引用来自“乾坤摄”的评论

不错,很有耐心的....
tks 这样慢慢就能学到东西了
乾坤摄
乾坤摄
不错,很有耐心的....
java ssh中使用uploadify 出现的貌似是版本问题

原本都好好的 ,突然重新部署了下服务器,发现本地和服务器上,用uploadify选中一个文件后,在上传文件队列中显示的文件名字有中文的都是乱码了~~传到后台是正常的,只是显示由问题。经过各种...

忧郁麦芽
2013/09/11
1K
1
jQuery 1.9.1中live()变更

开始的时候在jQuery.1.7.1中使用了.live()觉得很好用,特别是在绑定事件之后再加入的元素的事件绑定上很方便(第一次live之后以后添加的元素就不需要绑定啦) 后来jQuery更新到1.9.1,页面中的...

FuniK
2013/12/20
0
0
jQuery的"特别事件"扩展

特别事件 翻译自http://brandonaaron.net/blog/2009/03/26/special-events 原作者:Brandon Aaron jQuery自1.2.2版开始引入称为"特别事件"的扩展API。These events are special because they......

Imy
2011/02/01
0
0
jQuery 1.4版本的15个新功能

jQuery 1.4版本的15个新功能 1.jQuery()创建DOM元素:支持传参设置属性 之前,jQuery可以通过 attr 方法设置元素的属性,既可传属性的名和值,也可以是包含几组特定 属性名值对 的 对象。在 ...

Sephiroth
2010/01/28
858
1
jQuery 1.10.0 和 2.0.1 发布

jQuery 团队今天发布了两个更新版本,分别是 1.10.0 和 2.0.1,改进内容: jQuery 1.10.0 Changelog Ajax #13922: HEAD responses with application/json results parseerror #13388: Ajax ......

oschina
2013/05/25
3.9K
7

没有更多内容

加载失败,请刷新页面

加载更多

解决vim打开之后乱码的问题

在Windows中的文档,传输到Linux系统中(使用rz命令),出现乱码 root@localhost ~]# rpm -qf `which iconv` glibc-common-2.17-105.el7.x86_64 [root@localhost ~]# rpm -ihv /mnt/Packages......

寰宇01
21分钟前
0
0
aldi 2017年1月记录

../../tools/CBLAS/lib/cblas_LINUX.a ../../tools/lapack-3.4.2/liblapacke.a \../../tools/lapack-3.4.2/librefblas.a -lgfortran \../../tools/lapack-3.4.2/liblapack.a \../../......

MtrS
22分钟前
0
0
Choerodon如何进行日志收集与告警

作者:董文启 应用程序日志是由软件应用程序记录的事件文件, 它一般包含错误,信息事件和警告。一个良好的日志系统有助于快速发现问题,定位问题,同时也为业务分析起到一定的作用。 传统E...

Choerodon
34分钟前
1
0
js二维码生成插件“jquery.qrcode.min.js”

<!doctype html> <html> <head> <meta charset="utf-8" /> <title>生成二维码</title> <script type='text/javascript' src='http://cdn.staticfile.org/jquery/2.1.1/jquery.min.js'></scri......

泉天下
37分钟前
0
0
Spring AOP之同一个对象方法内部自调用导致事务失效问题

对于像我这种喜欢滥用AOP的程序员,遇到坑也是习惯了,不仅仅是事务,其实只要脱离了Spring容器管理的所有对象,对于SpringAOP的注解都会失效,因为他们不是Spring容器的代理类,SpringAOP,就切入不...

xiaomin0322
44分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部