轉一個比較牛的JS Hook實現,基於Function prototype,能夠勾住和釋放任何函式
阿新 • • 發佈:2018-11-19
基於原型的hook實現:
[bool]hook:params{ realFunc[String|must]:用於儲存原始函式的函式名稱,用於unHook; hookFunc[Function|must]:替換的hook函式; context[Object|opt]:目標函式所在物件,用於hook非window物件下的函式,如String.protype.slice,carInstance1 methodName[String|opt]:匿名函式需顯式傳入目標函式名eg:this.Begin = function(){....}; } [bool]unhook:params{ realFunc[String|must]:用於儲存原始函式的函式名稱,用於unHook; funcName[String|must]:被Hook的函式名稱 context[Object|opt]:目標函式所在物件,用於hook非window物件下的函式,如String.protype.slice,carInstance1 }
<!DOCTYPE html> <html> <head> <title> </title> <script type="text/javascript"> function Hooks(){ return { initEnv:function () { Function.prototype.hook = function (realFunc,hookFunc,context,funcName) { var _context = null; //函式上下文 var _funcName = null; //函式名 _context = context || window; _funcName = funcName || getFuncName(this); _context[realFunc] = this; if(_context[_funcName].prototype && _context[_funcName].prototype.isHooked){ console.log("Already has been hooked,unhook first"); return false; } function getFuncName (fn) { // 獲取函式名 var strFunc = fn.toString(); var _regex = /function\s+(\w+)\s*\(/; var patten = strFunc.match(_regex); if (patten) { return patten[1]; }; return ''; } try{ eval('_context[_funcName] = function '+_funcName+'(){\n'+ 'var args = Array.prototype.slice.call(arguments,0);\n'+ 'var obj = this;\n'+ 'hookFunc.apply(obj,args)\n'+ 'return _context[realFunc].apply(obj,args);\n'+ '};'); _context[_funcName].prototype.isHooked = true; return true; }catch (e){ console.log("Hook failed,check the params."); return false; } } Function.prototype.unhook = function (realFunc,funcName,context) { var _context = null; var _funcName = null; _context = context || window; _funcName = funcName; if (!_context[_funcName].prototype.isHooked) { console.log("No function is hooked on"); return false; } _context[_funcName] = _context[realFunc]; delete _context[realFunc]; return true; } }, cleanEnv:function () { if(Function.prototype.hasOwnProperty("hook")){ delete Function.prototype.hook; } if(Function.prototype.hasOwnProperty("unhook")){ delete Function.prototype.unhook; } return true; } }; } var hook = Hooks(); hook.initEnv(); // 這個是要執行的正常的函式 function test(){ alert('test'); } // 這個是鉤子函式。此鉤子函式內心戲: // 我只喜歡test函式,所以我必須出現在她前面(在她前面執行),這樣她才能看到我。 function hookFunc(){ alert('hookFunc'); } // hookFunc鉤住test test.hook(test,hookFunc,window,"test"); window.onload = function(){ // 由於鉤子函式hookFunc鉤住了test函式,所以test執行時,會先執行hookFunc。 test(); } </script> </head> <body> </body> </html>