• javaScript hook


    今天在网上搜索了不少资料,基本概念如下:

    钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

    钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。 

    转自:http://www.clanfei.com/2013/10/1730.html

    当我们面对比较复杂的前端项目时,我们经常会采用模块化的方式来对JavaScript代码进行解耦,以方便对代码的管理和维护,以下是一个简单的立即执行函数实现的模块化例子:

    var Common = (function(){
    //这个函数是立即执行的,执行结果给了Common
    var func = function(){ // 全局公用方法 } return { func : func } })(); var ModuleA = (function(){ var _count = 1; var init = function(){ // 独立模块逻辑 } var getCount = function(){ return _count; } return { init : init, getCount : getCount } })();

    模块只对外暴露外部需要的接口,而外部模块不需要关心其内部的运行逻辑,只需要知道调用接口的方式和返回结果,这样就实现了模块的“低耦合,高内聚”。

    看起来很美好,可是当项目的逻辑变的越来越复杂时,比如A模块中某个针对全局公用的逻辑,可能在B模块的某种特定情况下需要进行一些额外的逻辑操作,该怎么办呢?

    var Common = (function(){
        var func = function(){
            // 全局公用方法
            if(typeof ModuleA != 'undefined' && ModuleA.getCount() > 0){
                // 模块A需要进行的额外逻辑操作,实际上就是钩子捕获消息
            }
        }
        return {
            func : func
        }
    })();
     
    var ModuleA = (function(){
        var _count = 1;
        var init = function(){
            // 独立模块逻辑
        }
        var getCount = function(){
            return _count;
        }
        return {
            init : init,
            getCount : getCount
        }
    })();

    不知道当你看到Common.func中间的那一坨东西的时候,会不会突然怒吼一声:“卧槽,尼玛怎么这么恶心!”= =。。

    明明是A模块的逻辑,却恶心地出现在了公用模块里,如果这样的特殊逻辑多起来之后,Common模块会不会变成这样?

    var Common = (function(){
        var func = function(){
            // 全局公用方法
            if(typeof ModuleA != 'undefined' && ModuleA.getCount() > 0){
                // 模块A需要进行的额外逻辑操作
            }
            if(typeof ModuleB != 'undefined' && ModuleB.getWhat() != 'something'){
                // 模块B需要进行的额外逻辑操作
            }
            // ...
            if(typeof ModuleZ != 'undefined' && ModuleB.isWhat() !== false){
                // 模块Z需要进行的额外逻辑操作
            }
        }
        return {
            func : func
        }
    })();

    天哪,简直无法忍受。。

    如果。。如果有这么一个钩子(Hook),可以把额外的逻辑代码挂在Common.func上,而Common.func执行的时候顺便把钩子上挂着的代码也执行了,那该多好啊。。这样的话既可以实现特殊的额外操作,又可以保持模块的低耦合和高内聚:

    var Common = (function(){
            //这个函数是立即执行的,执行结果给了Common
            var func = function(){
                //执行挂在这个方法的钩子上的所有额外逻辑代码
                var arg = 2;
    
                Hook.doActions(arg);//每个模块都可以得到arg,根据它做相应操作。但是并不能更改arg;
                console.log(arg);
                //全局公用方法
            }
            return {
                func: func
            }
        })()
        //应用场景:比如A模块中某个针对全局公用的逻辑,可能在B模块的某种特定情况下需要进行一些额外的逻辑操作。
        var ModuleA = (function(){
            var _count = 1;
            var init = function(){
                //用钩子把额外的逻辑挂到Common.func上
                Hook.addAction(Common.func, function(arg){
                    if(_count > 0){
                        //增加的额外逻辑操作
                        arg = arg + 1;
                        console.log("看看执行到没?");
                        console.log(arg);
                    }
                })
            }
            var getCount = function(){
                return _count;
            }
            return {
                init: init,
                getCount: getCount
            }
        })()
        ModuleA.init();
        Common.func();

    没有不可能。借鉴了一下WordPress的Hook机制,一个基于JavaScript钩子机制模块就实现了。

    当然,一个完整的钩子机制需要考虑的并不像上面说的那么简单,具体的实现大家请看代码,或者懒得看的可以自己尝试实现,我就不在赘述了:

    <script>
    
            /*var fn1 = {
             _hooks : {
             actions:[
             {action:action,priority:priority},
             {}
             ],
             filters:[
             {
             filter: filter,
             priortity: priority
             }
             ]
             }
             }*/
    
            var Hook = (function(){
                var addAction = function(method, action, priority){
                    _initHook(method);
                    var actions = method['_hooks_'].actions;
                    actions.push({
                        action: action,
                        priority: priority || 10,
                    })
                    actions.sort(_compare);
                }
    
                var doActions = function(){
                    var method = Hook.doActions.caller;
              //caller:http://www.cnblogs.com/darr/p/4756906.html console.log(arguments.callee);
    //callee; //Common.func //指向调用它的函数 //如果一个函数f是在全局作用域内被调用的,则f.caller为null,相反,如果一个函数是在另外一个函数作用域内被调用的,则f.caller指向调用它的那个函数. _initHook(method); //Common.func._hooks_:{actions:[],filters:[]} var actions = method['_hooks_'].actions; if(arguments.length == 0){ arguments = method.arguments;//? } for(var i in actions){ if(actions[i].action.apply(method, arguments) === false){
                  //apply:http://www.cnblogs.com/darr/p/4757082.html
    return false; } } } var hasAction = function(method, action){ _initHook(method); var actions = method['_hooks_'].actions; if(actions.length > 0 && action != undefined){ for(var i in actions){ if(actions[i].action == action){ return true; } } return false; }else{ return actions.lengths > 0; } } var removeAction = function(method, action){ _initHook(method); var actions = method['_hooks_'].actions; if(actions.length > 0){ if(actions != undefined){ for(var i in actions){ if(actions[i].action == action){ delete actions[i]; return; } } }else{ method['_hooks_'].actions = []; } } } var addFilter = function(method, filter, priority){ _initHook(method); var filters = method['_hooks_'].filters; filters.push({ filter:filter, priority: priority || 10 }); filters.sort(_compare) } var applyFilters = function(value){ var method = Hook.applyFilters.caller; _initHook(method); var filters = method['_hooks_'].filters; for(var i in filters){ value = filters[i].filter.call(method, value); } return value; } var hasFilter = function(method, filter){ _initHook(method); var filters = method['_hooks_'].filters; if(filters.length > 0 && filter != undefined){ for(var i in filters){ if(filters[i] == filter){ return true; } } return false; }else{ return filters.length > 0 ; } } var removeFilter = function(method, filter){ _initHook(method); var filters = method['_hooks_'].filters; if(filters.length > 0){ if(filter != undefined){ for(var i in filters){ if(filters[i] == filter){ delete filters[i]; return; } } }else{ //filters = []; //有坑啊,不能用filters。应该将method['_hooks_'].filters指向空地址 method['_hooks_'].filters = []; } } } var _compare = function(hook1, hook2){ return hook1.priority < hook2.priority; } var _initHook = function(method){ if(!method['_hooks_']){ method['_hooks_'] = { actions: [], filters: [] } } } return { addAction: addAction, doActions: doActions, hasAction: hasAction, removeAction: removeAction, addFilter: addFilter, applyFilters: applyFilters, hasFilter: hasFilter, removewFilter: removeFilter } })(); </script>

     像适配器模式:http://www.cnblogs.com/tomxu/archive/2012/04/11/2435452.html

     像观察者模式:http://www.cnblogs.com/TomXu/archive/2012/03/02/2355128.html

  • 相关阅读:
    【弹道】Cocos 跟踪导弹
    腾讯云短信测试 (云短信、短信验证码)
    【组件】战斗力滚动数字
    Navicat访问远程服务器数据库
    解决Python读取SQL Server中文乱码问题
    【前端】GIS及JS题目
    【Postgres】空间计算
    PYTHONPATH在vscode和pycahrm的区别?为什么有的代码在vscode导入报错,pycahrm正常?精通PYTHONPATH作用真的很重要
    python 快速万能同步转异步语法
    fastjson序列化显示出null值的键值对
  • 原文地址:https://www.cnblogs.com/darr/p/4760502.html
Copyright © 2020-2023  润新知