jquery源码之神奇的钩子hooks

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)