钩子机制(hook)

it2022-05-09  63

钩子是编程惯用的一种手法,用来解决一种或多种特殊情况的处理。

简单来说,钩子就是适配器原理,或者说是表驱动原理,我们预先定义了一些钩子,在正常的代码逻辑中使用钩子去适配一些特殊的属性,样式或事件,这样可以让我们少写很多 else if 语句。

如果还是很难懂,看一个简单的例子,举例说明 hook 到底如何使用:

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 // 如果不用钩子的情况 // 考生分数以及父亲名 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); }

可以看到,在中间审阅考生这个函数中,运用了很多 else if 来判断是否考生有后门关系,如果现在业务场景发生变化,又多了几名考生,那么 else if 势必越来越复杂,往后维护代码也将越来越麻烦,成本很大,那么这个时候如果使用钩子机制,该如何做呢?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 // relationHook 是个钩子函数,用于得到关系得分 var  relationHook = {      "xijinping" : 1000,         "ligang" : 100,      "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); }

可以看到,使用钩子去处理特殊情况,可以让代码的逻辑更加清晰,省去大量的条件判断,上面的钩子机制的实现方式,采用的就是表驱动方式,就是我们事先预定好一张表(俗称打表),用这张表去适配特殊情况。当然 jQuery 的 hook 是一种更为抽象的概念,在不同场景可以用不同方式实现。

看看 jQuery 里的表驱动 hook 实现,$.type 方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ( function (window, undefined) {      var          // 用于预存储一张类型表用于 hook          class2type = {};        // 原生的 typeof 方法并不能区分出一个变量它是 Array 、RegExp 等 object 类型,jQuery 为了扩展 typeof 的表达力,因此有了 $.type 方法      // 针对一些特殊的对象(例如 null,Array,RegExp)也进行精准的类型判断      // 运用了钩子机制,判断类型前,将常见类型打表,先存于一个 Hash 表 class2type 里边      jQuery.each( "Boolean Number String Function Array Date RegExp Object Error" .split( " " ),  function (i, name) {          class2type[ "[object "  + name +  "]" ] = name.toLowerCase();      });        jQuery.extend({          // 确定JavaScript 对象的类型          // 这个方法的关键之处在于 class2type[core_toString.call(obj)]          // 可以使得 typeof obj 为 "object" 类型的得到更进一步的精确判断          type:  function (obj) {                if  (obj ==  null ) {                  return  String(obj);              }              // 利用事先存好的 hash 表 class2type 作精准判断              // 这里因为 hook 的存在,省去了大量的 else if 判断              return  typeof  obj ===  "object"  ||  typeof  obj ===  "function"  ?                  class2type[core_toString.call(obj)] ||  "object"  :                  typeof  obj;          }      }) })(window);

这里的 hook 只是 jQuery 大量使用钩子的冰山一角,在对 DOM 元素的操作一块,attr 、val 、prop 、css 方法大量运用了钩子,用于兼容 IE 系列下的一些怪异行为。在遇到钩子函数的时候,要结合具体情境具体分析,这些钩子相对于表驱动而言更加复杂,它们的结构大体如下,只要记住钩子的核心原则,保持代码整体逻辑的流畅性,在特殊的情境下去处理一些特殊的情况:

1 2 3 4 5 6 7 8 9 var  someHook = {      get:  function (elem) {          // obtain and return a value          return  "something" ;      },      set:  function (elem, value) {          // do something with value      } }

从某种程度上讲,钩子是一系列被设计为以你自己的代码来处理自定义值的回调函数。有了钩子,你可以将差不多任何东西保持在可控范围内。

转载于:https://www.cnblogs.com/wang985850293/p/5623626.html


最新回复(0)