码迷,mamicode.com
首页 > Web开发 > 详细

jquery源码之神奇的钩子hooks

时间:2015-06-21 11:49:02      阅读:115      评论:0      收藏:0      [点我收藏+]

标签:

hook顾名思义,钩子,挂钩,即有钩子就挂在上面,否则就无需理会。钩子是编程惯用的一种手法,用来解决一种或多种特殊情况的处理。

设计模式中的模板模式中也有个钩子函数,它的含义是:父类提供一系列钩子,子类实现时可以自行选择是否挂钩。

在jquery中特殊样式(兼容性不好的样式)都是用hook解决的。

首先举了小例子,说说hook的好处吧,也看看hook到底是个何方神圣。

现在考公务员,要么靠实力,要么靠关系,但领导肯定也不会弄的那么明显,一般都是暗箱操作,这个场景用钩子实现再合理不过了。

 

// 如果不用钩子的情况
// 考生分数以及父亲名
function examinee(name, score, fatherName) {
	return {
		name: name,
		score: score,
		fatherName: fatherName
	};
}

// 审阅考生们
function judge(examinees) {
	var result = {};
	for (var i in examinees) {
		var curExaminee = examinees[i];
		var ret = curExaminee.score;
		// 判断是否有后门关系
		if (curExaminee.fatherName === ‘xijingping‘) {
			ret += 1000;
		} else if (curExaminee.fatherName === ‘ligang‘) {
			ret += 100;
		} else if (curExaminee.fatherName === ‘pengdehuai‘) {
			ret += 50;
		}
		result[curExaminee.name] = ret;
	}
	return result;
}


var lihao = examinee("lihao", 10, ‘ligang‘);
var xida = examinee(‘xida‘, 8, ‘xijinping‘);
var peng = examinee(‘peng‘, 60, ‘pengdehuai‘);
var liaoxiaofeng = examinee(‘liaoxiaofeng‘, 100, ‘liaodaniu‘);

var result = judge([lihao, xida, peng, liaoxiaofeng]);

// 根据分数选取前三名
for (var name in result) {
	console.log("name:" + name);
	console.log("score:" + score);
}

// 这样的话如果我们增加有后台的考生,成本会比较大,需要改动两个地方
// 并且代码块会越来越大,不适合阅读

 

  使用钩子则如下:

// 结果根据取决于最终积分
var relationHook = {
	"ligang": 100,
	"xijinping": 1000,
	"pengdehuai": 50
}
// 考生分数以及父亲名
function examinee(name, score, fatherName) {
	return {
		name: name,
		score: score,
		fatherName: fatherName
	};
}

// 审阅考生们
function judge(examinees) {
	var result = {};
	for (var i in examinees) {
		var curExaminee = examinees[i];
		var ret = curExaminee.score;
		if (relationHook[curExaminee.fatherName] ) {
			ret += relationHook[curExaminee.fatherName] ;
		}
		result[curExaminee.name] = ret;
	}
	return result;
}


var lihao = examinee("lihao", 10, ‘ligang‘);
var xida = examinee(‘xida‘, 8, ‘xijinping‘);
var peng = examinee(‘peng‘, 60, ‘pengdehuai‘);
var liaoxiaofeng = examinee(‘liaoxiaofeng‘, 100, ‘liaodaniu‘);

var result = judge([lihao, xida, peng, liaoxiaofeng]);

// 根据分数选取前三名
for (var name in result) {
	console.log("name:" + name);
	console.log("score:" + score);
}

  可能大家会觉得钩子的实现方式好熟悉,这不就是表驱动嘛。是的,他的实现方式的确是用的表驱动,但是hook是一种抽象的概念,在不同的场景可以用不同的方式实现。

通过上述例子,大家也看到了hook的方便性。扩展性,自我表达性都特别好。还很符合人的思维逻辑。(把有后台和没后台分开处理)

 

再让我们看看jquery中hooks的实现吧。由于浏览器兼容性差,jquery内部是有很多不同的hooks的,在这里就不一一列举了,就说说jquery.attr的实现:

jQuery.extend({
	
	attr: function( elem, name, value, pass ) {
		var ret, hooks, notxml,
			nType = elem.nodeType;

		// don‘t get/set attributes on text, comment and attribute nodes
		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
			return;
		}

		if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
			return jQuery( elem )[ name ]( value );
		}

		// Fallback to prop when attributes are not supported
		if ( typeof elem.getAttribute === "undefined" ) {
			return jQuery.prop( elem, name, value );
		}

		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );

		// All attributes are lowercase
		// Grab necessary hook if one is defined
		if ( notxml ) {
			name = name.toLowerCase();
			// 获取相应的hook, 这里主要是获取  attrHooks,
			hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
		}
        // 如果value存在,则设置对应属性值为value
		if ( value !== undefined ) {

			// value 为null,则删除该属性
			if ( value === null ) {
				jQuery.removeAttr( elem, name );
				return;
			// 如果hooks存在, 且hooks中有set属性,且不为xml,则执行该set方法,
			// 如果有返回值,则返回该返回值
			} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
				return ret;
			// 处理普通情况的属性赋值
			} else {
				elem.setAttribute( name, value + "" );
				return value;
			}

		// 如果value存在,则取出该属性对应的值	
		// 与上述钩子一样,处理特殊情况
		} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
			return ret;
		// 处理普通情况
		} else {
			ret = elem.getAttribute( name );

			// Non-existent attributes return null, we normalize to undefined
			return ret === null ?
				undefined :
				ret;
		}
	}
	// 再来看看钩子的实现
	attrHooks: {
		// 这个钩子只支持type和value
		type: {
			// type 是只有set的
			set: function( elem, value ) {
				// We can‘t allow the type property to be changed (since it causes problems in IE)
				if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
					jQuery.error( "type property can‘t be changed" );
				} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
					// Setting the type on a radio button after the value resets the value in IE6-9
					// Reset value to it‘s default in case type is set after value
					// This is for element creation
					var val = elem.value;
					elem.setAttribute( "type", value );
					if ( val ) {
						elem.value = val;
					}
					return value;
				}
			}
		},
		// Use the value property for back compat
		// Use the nodeHook for button elements in IE6/7 (#1954)
		value: {
			// value
			get: function( elem, name ) {
				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
					return nodeHook.get( elem, name );
				}
				return name in elem ?
					elem.value :
					null;
			},
			set: function( elem, value, name ) {
				// 内部实现也有嵌套使用nodeHook钩子
				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
					return nodeHook.set( elem, value, name );
				}
				// Does not return so that setAttribute is also used
				elem.value = value;
			}
		}
	},
});

  jQuery为了兼容各大浏览器,用了大量hook,如果没有这些hook,真不敢想象。。。

 

jquery源码之神奇的钩子hooks

标签:

原文地址:http://www.cnblogs.com/w2154/p/4591718.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!