首页 > 代码库 > 【repost】JS中的hook机制

【repost】JS中的hook机制

hook机制也就是钩子机制,由表驱动实现,常用来处理多种特殊情况的处理。我们预定义了一些钩子,在常用的代码逻辑中去适配一些特殊的事件,这样可以让我们少些很多if else语句。
举个高考加分的例子,比如获得过全国一等奖加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中大量的使用了钩子机制去做一些兼容。拿$.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中做了很多这样的变量保存。
另外
typeof new Number(1) //= "object"这好像不科学啊——但是new出来的就是一个对象啊,显然是我们的使用方式存在一些问题。应该是按如下方法使用:

Object.prototype.toString.call(new Number(1))         //= "[object Number]"

在这儿需要区别下两个概念:对象实例和字面值。
js中有5个基本数据类型:字符串、数值、布尔类型、null和undefined。只有字符串、数值和布尔数据类型有对应的构造方法对象。字符串、浮点数、整数和布尔值都是字面值。

我们可以使用严格相等性来比较一个对象实例和一个字面值

var str1 = String("string");
var num1 = Number(1.23);
var bool1 = Boolean(true);

if (str1 === "string") {
    console.log("equal");
}
if (num1 === 1.23) {
    console.log(‘equal‘);
}
if (bool1 === true) {
    console.log(‘equal‘);
}

var str2 = new String("string");
var num2 = new Number(1.23);
var bool2 = new Boolean(true);

if (str2 === "string") {
    console.log(‘equal‘);
} else {
    console.log(‘not equal‘);
}
if (num2 === 1.23) {
    console.log(‘equal‘);
} else {
    console.log(‘not equal‘);
}
if (bool2 === true) {
    console.log(‘equal‘);
} else {
    console.log(‘not equal‘);
}

//打印结果
equal
equal
equal
not equal
not equal
not equal

也就是基本类型变量(没有使用new创建的变量)严格的等于字面值,而对象实例则不会。
对于Object.prototype.toString方法更详细的介绍,可以参考这篇博客


除了做一些兼容或者定值的匹配,钩子机制在项目中能否使用呢?那我就做一个代码的搬运工,这是12年的一篇文章,介绍钩子机制在项目中的使用的 ,虽然这几年面向对象的写法在不断的丰富,不过,或许在某些方面我们仍能得到一点借鉴吧。

【repost】JS中的hook机制