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,真不敢想象。。。
原文:http://www.cnblogs.com/w2154/p/4591718.html