今天在网上搜索了不少资料,基本概念如下:

钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。 

转自:http://www.clanfei.com/2013/10/1730.html

当我们面对比较复杂的前端项目时,我们经常会采用模块化的方式来对JavaScript代码进行解耦,以方便对代码的管理和维护,以下是一个简单的立即执行函数实现的模块化例子:

  1. var Common = (function(){
    //这个函数是立即执行的,执行结果给了Common
  2. var func = function(){
  3. // 全局公用方法
  4. }
  5. return {
  6. func : func
  7. }
  8. })();
  9.  
  10. var ModuleA = (function(){
  11. var _count = 1;
  12. var init = function(){
  13. // 独立模块逻辑
  14. }
  15. var getCount = function(){
  16. return _count;
  17. }
  18. return {
  19. init : init,
  20. getCount : getCount
  21. }
  22. })();

模块只对外暴露外部需要的接口,而外部模块不需要关心其内部的运行逻辑,只需要知道调用接口的方式和返回结果,这样就实现了模块的“低耦合,高内聚”。

看起来很美好,可是当项目的逻辑变的越来越复杂时,比如A模块中某个针对全局公用的逻辑,可能在B模块的某种特定情况下需要进行一些额外的逻辑操作,该怎么办呢?

  1. var Common = (function(){
  2. var func = function(){
  3. // 全局公用方法
  4. if(typeof ModuleA != 'undefined' && ModuleA.getCount() > 0){
  5. // 模块A需要进行的额外逻辑操作,实际上就是钩子捕获消息
  6. }
  7. }
  8. return {
  9. func : func
  10. }
  11. })();
  12.  
  13. var ModuleA = (function(){
  14. var _count = 1;
  15. var init = function(){
  16. // 独立模块逻辑
  17. }
  18. var getCount = function(){
  19. return _count;
  20. }
  21. return {
  22. init : init,
  23. getCount : getCount
  24. }
  25. })();

不知道当你看到Common.func中间的那一坨东西的时候,会不会突然怒吼一声:“卧槽,尼玛怎么这么恶心!”= =。。

明明是A模块的逻辑,却恶心地出现在了公用模块里,如果这样的特殊逻辑多起来之后,Common模块会不会变成这样?

  1. var Common = (function(){
  2. var func = function(){
  3. // 全局公用方法
  4. if(typeof ModuleA != 'undefined' && ModuleA.getCount() > 0){
  5. // 模块A需要进行的额外逻辑操作
  6. }
  7. if(typeof ModuleB != 'undefined' && ModuleB.getWhat() != 'something'){
  8. // 模块B需要进行的额外逻辑操作
  9. }
  10. // ...
  11. if(typeof ModuleZ != 'undefined' && ModuleB.isWhat() !== false){
  12. // 模块Z需要进行的额外逻辑操作
  13. }
  14. }
  15. return {
  16. func : func
  17. }
  18. })();

天哪,简直无法忍受。。

如果。。如果有这么一个钩子(Hook),可以把额外的逻辑代码挂在Common.func上,而Common.func执行的时候顺便把钩子上挂着的代码也执行了,那该多好啊。。这样的话既可以实现特殊的额外操作,又可以保持模块的低耦合和高内聚:

  1. var Common = (function(){
  2. //这个函数是立即执行的,执行结果给了Common
  3. var func = function(){
  4. //执行挂在这个方法的钩子上的所有额外逻辑代码
  5. var arg = 2;
  6.  
  7. Hook.doActions(arg);//每个模块都可以得到arg,根据它做相应操作。但是并不能更改arg;
  8. console.log(arg);
  9. //全局公用方法
  10. }
  11. return {
  12. func: func
  13. }
  14. })()
  15. //应用场景:比如A模块中某个针对全局公用的逻辑,可能在B模块的某种特定情况下需要进行一些额外的逻辑操作。
  16. var ModuleA = (function(){
  17. var _count = 1;
  18. var init = function(){
  19. //用钩子把额外的逻辑挂到Common.func上
  20. Hook.addAction(Common.func, function(arg){
  21. if(_count > 0){
  22. //增加的额外逻辑操作
  23. arg = arg + 1;
  24. console.log("看看执行到没?");
  25. console.log(arg);
  26. }
  27. })
  28. }
  29. var getCount = function(){
  30. return _count;
  31. }
  32. return {
  33. init: init,
  34. getCount: getCount
  35. }
  36. })()
  37. ModuleA.init();
  38. Common.func();

没有不可能。借鉴了一下WordPress的Hook机制,一个基于JavaScript钩子机制模块就实现了。

当然,一个完整的钩子机制需要考虑的并不像上面说的那么简单,具体的实现大家请看代码,或者懒得看的可以自己尝试实现,我就不在赘述了:

  1. <script>
  2.  
  3. /*var fn1 = {
  4. _hooks : {
  5. actions:[
  6. {action:action,priority:priority},
  7. {}
  8. ],
  9. filters:[
  10. {
  11. filter: filter,
  12. priortity: priority
  13. }
  14. ]
  15. }
  16. }*/
  17.  
  18. var Hook = (function(){
  19. var addAction = function(method, action, priority){
  20. _initHook(method);
  21. var actions = method['_hooks_'].actions;
  22. actions.push({
  23. action: action,
  24. priority: priority || 10,
  25. })
  26. actions.sort(_compare);
  27. }
  28.  
  29. var doActions = function(){
  30. var method = Hook.doActions.caller;
              //caller:http://www.cnblogs.com/darr/p/4756906.html
  31. console.log(arguments.callee);
  32. //callee;
  33. //Common.func
  34. //指向调用它的函数
  35. //如果一个函数f是在全局作用域内被调用的,则f.caller为null,相反,如果一个函数是在另外一个函数作用域内被调用的,则f.caller指向调用它的那个函数.
  36. _initHook(method);
  37. //Common.func._hooks_:{actions:[],filters:[]}
  38. var actions = method['_hooks_'].actions;
  39. if(arguments.length == 0){
  40. arguments = method.arguments;//?
  41. }
  42. for(var i in actions){
  43. if(actions[i].action.apply(method, arguments) === false){
                  //apply:http://www.cnblogs.com/darr/p/4757082.html
  44. return false;
  45. }
  46. }
  47. }
  48.  
  49. var hasAction = function(method, action){
  50. _initHook(method);
  51. var actions = method['_hooks_'].actions;
  52. if(actions.length > 0 && action != undefined){
  53. for(var i in actions){
  54. if(actions[i].action == action){
  55. return true;
  56. }
  57. }
  58. return false;
  59. }else{
  60. return actions.lengths > 0;
  61. }
  62.  
  63. }
  64.  
  65. var removeAction = function(method, action){
  66. _initHook(method);
  67. var actions = method['_hooks_'].actions;
  68. if(actions.length > 0){
  69. if(actions != undefined){
  70. for(var i in actions){
  71. if(actions[i].action == action){
  72. delete actions[i];
  73. return;
  74. }
  75. }
  76. }else{
  77. method['_hooks_'].actions = [];
  78. }
  79. }
  80. }
  81.  
  82. var addFilter = function(method, filter, priority){
  83. _initHook(method);
  84. var filters = method['_hooks_'].filters;
  85. filters.push({
  86. filter:filter,
  87. priority: priority || 10
  88. });
  89. filters.sort(_compare)
  90. }
  91.  
  92. var applyFilters = function(value){
  93. var method = Hook.applyFilters.caller;
  94. _initHook(method);
  95. var filters = method['_hooks_'].filters;
  96. for(var i in filters){
  97. value = filters[i].filter.call(method, value);
  98. }
  99. return value;
  100. }
  101.  
  102. var hasFilter = function(method, filter){
  103. _initHook(method);
  104. var filters = method['_hooks_'].filters;
  105. if(filters.length > 0 && filter != undefined){
  106. for(var i in filters){
  107. if(filters[i] == filter){
  108. return true;
  109. }
  110. }
  111. return false;
  112. }else{
  113. return filters.length > 0 ;
  114. }
  115. }
  116.  
  117. var removeFilter = function(method, filter){
  118. _initHook(method);
  119. var filters = method['_hooks_'].filters;
  120. if(filters.length > 0){
  121. if(filter != undefined){
  122. for(var i in filters){
  123. if(filters[i] == filter){
  124. delete filters[i];
  125. return;
  126. }
  127. }
  128. }else{
  129. //filters = [];
  130. //有坑啊,不能用filters。应该将method['_hooks_'].filters指向空地址
  131. method['_hooks_'].filters = [];
  132. }
  133. }
  134. }
  135.  
  136. var _compare = function(hook1, hook2){
  137. return hook1.priority < hook2.priority;
  138. }
  139.  
  140. var _initHook = function(method){
  141. if(!method['_hooks_']){
  142. method['_hooks_'] = {
  143. actions: [],
  144. filters: []
  145. }
  146. }
  147. }
  148.  
  149. return {
  150. addAction: addAction,
  151. doActions: doActions,
  152. hasAction: hasAction,
  153. removeAction: removeAction,
  154. addFilter: addFilter,
  155. applyFilters: applyFilters,
  156. hasFilter: hasFilter,
  157. removewFilter: removeFilter
  158. }
  159. })();
  160. </script>

像适配器模式:http://www.cnblogs.com/tomxu/archive/2012/04/11/2435452.html

像观察者模式:http://www.cnblogs.com/TomXu/archive/2012/03/02/2355128.html

javaScript hook的更多相关文章

  1. XSS攻击:获取浏览器记住的明文密码

    作者:余弦(@evilcos) 0x01. XSS获取明文密码的多种方式 我已经感受到Web潮流带来的巨大革新,尤其是最近HTML5越来越火.浏览器们在客户端瓜分着这个Web OS,只要是对用户体验好 ...

  2. CSS架构目标

    擅长CSS的Web开发人员不仅可以从视觉上复制实物原型,还可以用代码进行完美的呈现.无需使用表格.尽可能少的使用图片.如果你是个名副其实的高手,你可以快速把最新和最伟大的技术应用到你的项目中,比如媒体 ...

  3. css best practice for big team and project

    推荐查看以下文章: https://segmentfault.com/a/1190000000704006 关于BEM,SMACSS,OOCSS的通俗易懂的介绍 http://philipwalton ...

  4. [hook.js]通用Javascript函数钩子及其他

    2013.02.16<:article id=post_content> 最近看Dom Xss检测相关的Paper,涉及到Hook Javascript函数,网上翻了一下,貌似没有什么通用 ...

  5. JavaScript常用的Hook脚本

    JavaScript常用的Hook脚本 本文Hook脚本 来自 包子 页面最早加载代码Hook时机 在source里 用dom事件断点的script断点 然后刷新网页,就会断在第一个js标签,这时候就 ...

  6. 闭包传参 余额计算 钩子hook 闭包中的this JavaScript 钩子

    闭包传参  余额计算    钩子hook 小程序 a=function(e){console.log(this)}() a=function(e){console.log(this)}() VM289 ...

  7. javascript单元测试框架mochajs详解

    关于单元测试的想法 对于一些比较重要的项目,每次更新代码之后总是要自己测好久,担心一旦上线出了问题影响的服务太多,此时就希望能有一个比较规范的测试流程.在github上看到牛逼的javascript开 ...

  8. JavaScript学习笔记(四)——jQuery插件开发与发布

    jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...

  9. JavaScript学习总结(四)——jQuery插件开发与发布

    jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...

随机推荐

  1. Android 异常处理最佳实践

    一个好的app 异常处理机制 我认为应该至少包含以下几个功能: 1.能把错误信息上传到服务器  让开发者可以持续改进app 2.错误信息至少应该包含 是否在主进程 是否在主线程 等可以帮助程序员定位的 ...

  2. suse下设置IP的两种方法

    /Files/yzhxhwt/DB_51aspx.rar 第一种SUSE Linux IP设置方法ifconfig eth0 192.168.1.22 netmask 255.255.255.0 up ...

  3. 设置TextView控件的背景透明度和字体透明度

    TextView tv = (TextView) findViewById(R.id.xx); 第1种:tv.setBackgroundColor(Color.argb(255, 0, 255, 0) ...

  4. hdu 5256 LIS变形

    给一个数列,问最少修改多少个元素使数列严格递增.如果不是要求“严格”递增,那就是求最长不降子序列LIS,然后n-LIS就是答案.要严格递增也好办,输入的时候用每个数减去其下标处理一下就行了. /* * ...

  5. 迅影QQ视频查看v2.0 源码

    骗了1200多位朋友,实在惭愧,现在公开我自己的源码实现.本人新人,代码很烂,请凑合看吧O(∩_∩)O~ Form1.cs using System; using System.Text.Regula ...

  6. Request、Request.Form、Request.QueryString 用法的区别

    Request.Form:获取以POST方式提交的数据. Request.QueryString:获取地址栏参数(以GET方式提交的数据). Request:包含以上两种方式(优先获取GET方式提交的 ...

  7. spark connect to Cassandra problem

    Cassandra rowkey is Blob type, cannot select by spark. How?

  8. Select模型及tcp select模型

    参考:http://m.blog.csdn.net/article/details?id=51420015 一.套接字模式 套接字模式简单的决定了操作套接字时,Winsock函数是如何运转的.Wins ...

  9. Uva 11183 - Teen Girl Squad (最小树形图)

    Problem ITeen Girl Squad Input: Standard Input Output: Standard Output You are part of a group of n  ...

  10. 【转】大数据以及Hadoop相关概念介绍

    原博文出自于: http://www.cnblogs.com/xdp-gacl/p/4230220.html 感谢! 一.大数据的基本概念 1.1.什么是大数据 大数据指的就是要处理的数据是TB级别以 ...