什么是鈎子機制?使用鈎子機制有什么好處?
鈎子機制也叫hook機制,或者你可以把它理解成一種匹配機制,就是我們在代碼中設置一些鈎子,然后程序執行時自動去匹配這些鈎子;這樣做的好處就是提高了程序的執行效率,減少了if else 的使用同事優化代碼結構。由於js是單線程的編程語言,所以程序的運行效率在前端開發是比較重要的,在開發中我們秉承如果能用switch case 的地方就不要用if else 可以用hook實現的盡量使用hook機制去實現。
hook機制也就是鈎子機制,由表驅動實現,常用來處理多種特殊情況的處理。我們預定義了一些鈎子,在常用的代碼邏輯中去適配一些特殊的事件,這樣可以讓我們少些很多if else語句。
JS中的鈎子(hook)的例子
JS中的鈎子(hook)的例子1:
例如我們在向后台進行ajax請求的時候,后台經常會返回我們一些常見的錯誤碼,如:001代表用戶不存在,002代表用戶密碼輸入錯誤。003代表用戶被鎖定。這個時候我們要將錯誤友好的提示給用戶。這個時候我們該怎樣實現呢?
一般的寫法可能是:
$.ajax(option,function(result){ var errCode = result.errCode ;//錯誤碼 if(errCode){ if(errCode =='001'){ alert("用戶不存在") }else if(errCode =='002'){ alert("密碼輸入錯誤") }else if(errCode =='003'){ alert("用戶被鎖定") } }else{ //登錄成功 } },function(err){ })
這樣寫其實是比較low低,稍微有點經驗的可能會使用switch case來實現,但是這個兩種寫法都無法避免一個問題就是如果我的錯誤碼特別多,那得寫多少個if else和case 啊?但是如果使用hook寫法的話就會簡單好多,
首先我們先聲明一個錯誤碼鈎子列表
var codeList = { "001":"用戶不存在", "002":"密碼輸入錯誤", "003":"用戶被鎖定" } $.ajax(option,function(result){ var errCode = result.errCode ;//錯誤碼 if(!errCode){ alert(codeList[errCode]); }else{ //登錄成功 } },function(err){ })
這樣寫的話代碼結構更加清楚明了。這個例子是最簡單的應用了的了。
JS中的鈎子(hook)的例子2:
舉個高考加分的例子,比如獲得過全國一等獎加20分,二等獎加10分,三等獎加5分。使用if else的話:
function student(name,score,praise){ return { name:name, score:score, praise:praise } } function praiseAdd(students){ var results={}; for (var i in students){ var curStudent=students[i]; var ret=curStudent.score; if(curStudent.praise==1){ ret+=20; }else if(curStudent.praise==2){ ret+=10; }else if(curStudent.praise==3){ ret+=5; } results[curStudent.name]=ret; } return results; } var liming= student("liming",70,1); var liyi= student("liyi",90,2); var liuwei= student("liuwei",80,3); var ertuzi= student("ertuzi",85,3); var result=praiseAdd([liming,liyi,liuwei,ertuzi]); for(var i in result){ console.log("name:"+i+",score:"+result[i]); }
如果是用鈎子機制呢
function student(name,score,praise){ return { name:name, score:score, praise:praise } } var praiseList={ 1:20, 2:10, 3:5 } function praiseAdd(students){ var results={}; for (var i in students){ var curStudent=students[i]; var ret=curStudent.score; if(praiseList[curStudent.praise]) ret+=praiseList[curStudent.praise]; results[curStudent.name] = ret; } return results; } var liming= student("liming",70,1); var liyi= student("liyi",90,2); var liuwei= student("liuwei",80,3); var ertuzi= student("ertuzi",85,3); var result=praiseAdd([liming,liyi,liuwei,ertuzi]); for(var i in result){ console.log("name:"+i+",score:"+result[i]); }
所以簡單的說,其實鈎子機制就是利用一張表去匹配,而不是一次次的if條件判斷。
Jquery 中使用hook機制的例子
Jquery 中使用hook機制的例子1:
在Jquery 中hook機制被大量的使用,這里我們就Jquery中判斷變量類型的type方法來具體看一下
通常我們在js中判斷一個變量的數據類型?首先會想到type of 和 instanceof
如果是基本類型我們可以直接使用typeof,但是這種方式只能判斷基本數據類型,如果是對象,它返回結果都市Object,如果變量是null它返回的也是Object。這個時候我們要准確的判斷一般的寫法可能會是:
function type(obj){ var type = ""; if(obj==null){ type = null; }else{ type = obj.a.constructor.toString().split("(")[0].split(" ")[1] } return type; }
在jquery中的實現是:
var class2type={}; var toString = Object.prototype.toString; jQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol",function(index,name){ class2type["Object"+" name"]==name.toLowerCase(); }) type:function(obj){ if(obj==null){ return obj+""; } return typeof obj =="Object"||typeof obj ==="function"?class2type[toString.call(obj)]|||"object":typeof obj }
上面代碼中
class2type = { ‘[object Boolean]’: ‘boolean’, ‘[object Number]’: ‘number’, ‘[object String]’: ‘string’, ‘[object Function]’: ‘function’, ‘[object Undefined]’: ‘undefined’, ‘[object Null]’: ‘null’, ‘[object Array]’: ‘array’, ‘[object Date]’: ‘date’, ‘[object RegExp]’: ‘regexp’, ‘[object Object]’: ‘object’, ‘[object Error]’: ‘error’};
設置一個類型鈎子對象
toString.call(obj)就是Object.prototype.toString.call(arg)來細致判斷obj的類型。在這里則轉換成對象對應索引是否在class2type 中存在相應value,若存在則返回value判斷,若不存在則返回object類型。
這樣就實現了類型的判斷。
Jquery 中使用hook機制的例子2:
jQuery中大量的使用了鈎子機制去做一些兼容。拿$.type方法為例:
(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);
core_toString是定義了一個空對象,然后保存toString()方法。
var core={}; var core_toString=core.toString;
這樣后邊就可以直接調用Object.prototype.toString()方法,而不用每次都再去原型鏈上去找,節約了很多開銷,jQuery中做了很多這樣的變量保存。