欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Hook 函数详解:一种实用的编程技巧

最编程 2024-02-11 22:40:05
...

什么是钩子函数?

钩子函数是Windows消息处理机制的一部分,通过设置“钩子”,应用程序可以在系统级对所有消息、事件进行过滤,访问在正常情况下无法访问的消息。钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统 --- 百度百科的定义

我的理解是:钩子函数可以 钩住 我喜欢的东西(在window中就是我喜欢的消息),这应该就是钩子函数叫钩子函数的原因吧。。?

钩子函数的意义(用处)在于:我写了一个window程序,在程序中我写了一段代码(调用window的api来实现钩子),这段代码被系统通过系统调用,把其挂入系统中,然后我就可以对我感兴趣的消息进行处理,

我写的这段代码包含有一个回调函数,当有我喜欢的消息发出时,这个回调函数就会执行,所以说,钩子就是指的回调函数

下面是一个程序挂载全局钩子从而被360拦截的例子(其实360也有钩子,不然怎么知道别人要挂载钩子呢?即360可以拦截“挂载钩子”的消息。这个弹窗就是在360的钩子函数中创建的)

那么对于前端,什么是钩子函数呢?

对于前端来说,钩子函数就是指再所有函数执行前,我先执行了的函数,即 钩住 我感兴趣的函数,只要它执行,我就先执行。此概念(或者说现象)跟AOP(面向切面编程)很像

一个钩子函数的例子

 1 function Hooks(){
 2     return {
 3         initEnv:function () {
 4             Function.prototype.hook = function (realFunc,hookFunc,context,funcName) {
 5                 var _context = null; //函数上下文
 6                 var _funcName = null; //函数名
 7 
 8                 _context = context || window;
 9                 _funcName = funcName || getFuncName(this);
10                 _context[realFunc] = this;
11 
12                 if(_context[_funcName].prototype && _context[_funcName].prototype.isHooked){
13                     console.log("Already has been hooked,unhook first");
14                     return false;
15                 }
16                 function getFuncName (fn) {
17                     // 获取函数名
18                     var strFunc = fn.toString();
19                     var _regex = /function\s+(\w+)\s*\(/;
20                     var patten = strFunc.match(_regex);
21                     if (patten) {
22                         return patten[1];
23                     };
24                     return '';
25                 }
26                 try{
27                     eval('_context[_funcName] = function '+_funcName+'(){\n'+
28                         'var args = Array.prototype.slice.call(arguments,0);\n'+
29                         'var obj = this;\n'+
30                         'hookFunc.apply(obj,args)\n'+
31                         'return _context[realFunc].apply(obj,args);\n'+
32                         '};');
33                     _context[_funcName].prototype.isHooked = true;
34                     return true;
35                 }catch (e){
36                     console.log("Hook failed,check the params.");
37                     return false;
38                 }
39             }
40             Function.prototype.unhook = function (realFunc,funcName,context) {
41                 var _context = null;
42                 var _funcName = null;
43                 _context = context || window;
44                 _funcName = funcName;
45                 if (!_context[_funcName].prototype.isHooked)
46                 {
47                     console.log("No function is hooked on");
48                     return false;
49                 }
50                 _context[_funcName] = _context[realFunc];
51                 delete _context[realFunc];
52                 return true;
53             }
54         },
55         cleanEnv:function () {
56             if(Function.prototype.hasOwnProperty("hook")){
57                 delete Function.prototype.hook;
58             }
59             if(Function.prototype.hasOwnProperty("unhook")){
60                 delete Function.prototype.unhook;
61             }
62             return true;
63         }
64     };
65 }
66 
67 var hook = Hooks();
68 hook.initEnv();
69 
70 // 这个是要执行的正常的函数
71 function test(){
72     alert('test');
73 }
74 
75 // 这个是钩子函数。此钩子函数内心戏:
76 // 我只喜欢test函数,所以我必须出现在她前面(在她前面执行),这样她才能看到我。
77 function hookFunc(){
78     alert('hookFunc');
79 }
80 
81 // hookFunc钩住test
82 test.hook(test,hookFunc,window,"test");
83 
84 window.onload = function(){
85   // 由于钩子函数hookFunc钩住了test函数,所以test执行时,会先执行hookFunc。
86   test();
87 }