什么是鈎子函數?
鈎子函數是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 }