什么是鈎子機制?使用鈎子機制有什么好處?
鈎子機制也叫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中做了很多這樣的變量保存。

