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
javaScript hook的更多相关文章
- XSS攻击:获取浏览器记住的明文密码
作者:余弦(@evilcos) 0x01. XSS获取明文密码的多种方式 我已经感受到Web潮流带来的巨大革新,尤其是最近HTML5越来越火.浏览器们在客户端瓜分着这个Web OS,只要是对用户体验好 ...
- CSS架构目标
擅长CSS的Web开发人员不仅可以从视觉上复制实物原型,还可以用代码进行完美的呈现.无需使用表格.尽可能少的使用图片.如果你是个名副其实的高手,你可以快速把最新和最伟大的技术应用到你的项目中,比如媒体 ...
- css best practice for big team and project
推荐查看以下文章: https://segmentfault.com/a/1190000000704006 关于BEM,SMACSS,OOCSS的通俗易懂的介绍 http://philipwalton ...
- [hook.js]通用Javascript函数钩子及其他
2013.02.16<:article id=post_content> 最近看Dom Xss检测相关的Paper,涉及到Hook Javascript函数,网上翻了一下,貌似没有什么通用 ...
- JavaScript常用的Hook脚本
JavaScript常用的Hook脚本 本文Hook脚本 来自 包子 页面最早加载代码Hook时机 在source里 用dom事件断点的script断点 然后刷新网页,就会断在第一个js标签,这时候就 ...
- 闭包传参 余额计算 钩子hook 闭包中的this JavaScript 钩子
闭包传参 余额计算 钩子hook 小程序 a=function(e){console.log(this)}() a=function(e){console.log(this)}() VM289 ...
- javascript单元测试框架mochajs详解
关于单元测试的想法 对于一些比较重要的项目,每次更新代码之后总是要自己测好久,担心一旦上线出了问题影响的服务太多,此时就希望能有一个比较规范的测试流程.在github上看到牛逼的javascript开 ...
- JavaScript学习笔记(四)——jQuery插件开发与发布
jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...
- JavaScript学习总结(四)——jQuery插件开发与发布
jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...
随机推荐
- 【英语】Bingo口语笔记(63) - 一个单词的多种发音
- 2015-10-13 晴 tcp/ip卷1
今年看tcp/ip卷1的内容.苦和甜来自外界,坚强则来自内心,来自一个人的自我努力. 只有勤奋和积极进取的人 才会赢得成功的人生.加油
- 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:2.搭建环境-2.3配置共享磁盘
2.3.配置共享磁盘 2.3.1.创建共享磁盘 在cmd中进入WMware Workstation 10.0 安装目录: 1.创建存储Oracle Clusterware文件 (Oracle Clu ...
- JSTL笔记(胖先生版)
今天系统的学习了一下jstl,来记录一下. 在学习jstl以前,先要引两个jar包,然后再加入标签: <%@ taglib prefix="c" uri="http ...
- Tomcat: localhost:8080 提示404
下午配置环境,配置完成后,欣喜地进入localhost:8080,结果给我提示404 心想:尼玛,这localhost都还会404,这不坑爹吗?! 琢磨了好久,结果被我搞定了,只需要做一个改动: 打开 ...
- Oracle11g安装出现em.ear
在windows 7下安装Oracle 11g R2 时大概安装到45%时 提示找不到em.ear文件,如果点击继续还会出现其他错误,最后安装不成功. 检查文件发现另外一个zip没有解压 解压第二个压 ...
- JavaScript/jQuery 表单美化插件小结
Niceforms Niceforms是一款独立的表单美化工具,当前版本为2.0 官方主页:http://www.emblematiq.com/lab/niceforms/ 官方演示:http://w ...
- Java并发编程-总纲
Java 原生支持并发,基本的底层同步包括:synchronized,用来标示一个方法(普通,静态)或者一个块需要同步执行(某一时刻,只允许一个线程在执行代码块).volatile,用来标识一个变量是 ...
- OpenERP 7.0 中文报表PDF乱码(WindowsXP)
OpenERP默认安装输出的PDF中文报表都是一些方块: 此问题可以通过oecn_base_fonts模块解决: 更多关于oecn_base_fonts的信息请参考: 1. OpenERPv7.0 中 ...
- STM32 UART 重映射
在进行原理图设计的时候发现管脚的分配之间有冲突,需要对管脚进行重映射,在手册中了解到STM32 上有很多I/O口,也有很多的内置外设像:I2C,ADC,ISP,USART等 ,为了节省引出管脚,这些内 ...