用JavaScript对JSON进行模式匹配 (Part 2 - 实现)


Posted in Javascript onJuly 17, 2010

Notify & Capture
要实现 notify 和 capture 就太容易了,我们只需要把 capture 传入的 handler 都保存下来,然后在 notify 里面找到匹配的 handler 就可以了。

var filterHandlerBundles = []; 
Dispatch.capture = function(pattern, handler) { 
var filter = createFilter(pattern); 
filterHandlerBundles.push({ 
"filter": filter, 
"handler": handler 
}); 
}; 
Dispatcher.notify = function(json) { 
for (var i = 0; i < filterHandlerBundles.length; i++) { 
if (filterHandlerBundles[i].filter.apply(this, arguments)) { 
filterHandlerBundles[i].handler(json); 
} 
} 
};

这段代码的逻辑很清晰,关键就在于 createFilter 的部分。这个函数负责把一个描述模式的 JSON 转换为一个判断 JSON 是否匹配的函数。
Operators
我们设计了不少的运算法,如何实现他们呢?记住,我们不要 switch case 。因此,我们使用一个关联数组来保存运算符与实现之间的映射关系好了


var operators = {}; 
operators["lt"] = function(testValue, value) { 
return arguments.length == 2 && value < testValue; 
}; 
operators["lte"] = function(testValue, value) { 
return arguments.length == 2 && value <= testValue; 
}; 
operators["gt"] = function(testValue, value) { 
return arguments.length == 2 && value > testValue; 
}; 
operators["gte"] = function(testValue, value) { 
return arguments.length == 2 && value >= testValue; 
};

这样我们只要把 "$" 后面的运算符抽取出来,就可以立即找到对应的判断函数了。上面4个是比较运算符,由于实现比较容易,所以放在这里做例子。
一个比较难的函数是 eq ,因为它需要根据数据类型来选择具体的判断方式。对于 String 、 Number 、 Boolean , eq 的含义就是 == ;对于 Array , eq 的含义就是里面的每一个元素都 eq ,而且顺序一致;对于 Object , eq 的含义是每一个子条件都符合,因此我们需要将每一个子条件的运算符字符串提取出来,然后调用对应的运算符。具体可以参考完整代码。
其他运算符会简单一些,在此我仅仅给出提示,大家可以根据自己的实际需求这些运算符的子集或超集:

in - 遍历数组,看能否找到至少一个 eq 的。
all - 遍历数组,看是否每一个都存在 eq 的。
ex - 如果有传入值,则子元素存在。
re - 用正则表达式判断字符串是否匹配。
ld - 直接调用函数进行判断。
写好了吗?不太确信自己写得是否正确?这是我们下一篇文章要讨论的内容,让我们先加上一个默认运算符。

operators[""] = function(testValue, value) { 
if (testValue instanceof Array) { 
return operators["in"].apply(this, arguments); 
} else if (testValue instanceof RegExp) { 
return operators["re"].apply(this, arguments); 
} else if (testValue instanceof Function) { 
return operators["ld"].apply(this, arguments); 
} else { 
return operators["eq"].apply(this, arguments); 
} 
};

为什么需要一个默认运算符?这其实只是一个快捷方式。在大多数时候,我们需要的都是 eq 运算,如果每一处都要把运算符写上,代码将变得很复杂,也不美观。对比一下两个 JSON ,你觉得哪个更自然?
Dispatcher.capture({ 
"status": 200, 
"command": "message" 
}, function(json) { /* display message */ }); 
Dispatcher.capture({ 
"status$eq": 200, 
"command$eq": "message" 
}, function(json) { /* display message */ });

显然,第一个更直观一些。因此,我们需要一个默认运算符,当运算符字符串就是 "" 时,就通过默认运算符选择一个运算符。
Pattern to Filter
最后,我们需要把 operators 和 createFilter 接上。这部分工作其实也不难,只要调用默认运算符就可以了。
var createFilter = function(condition) { 
return function(json) { 
if (arguments.length > 0) { 
return operators[""](condition, json); 
} else { 
return operators[""](condition); 
} 
}; 
};

为什么需要考虑 json 参数没有传入的情况?下次文章再告诉你。不这样做也可以,只是有些很细小的问题而已。
写运算符,最需要的是严谨性。因为 Dispatcher 是一个封装好的组件,运算符一点点的不严谨,都会把缺陷埋藏得很深,很难找出来。因此,下一篇文章我们要讨论的是单元测试,通过单元测试我们可以大大提高 Dispatcher 的健壮性。
Javascript 相关文章推荐
疯掉了,尽然有js写的操作系统
Apr 23 Javascript
document.forms用法示例介绍
Jun 26 Javascript
JS常见问题之为什么点击弹出的i总是最后一个
Jan 05 Javascript
JS清除文本框内容离开在恢复及鼠标离开文本框时触发js的方法
Jan 12 Javascript
BootStrap中的表单大全
Sep 07 Javascript
JS制作图形验证码实现代码
Oct 19 Javascript
详解AngularJS2 Http服务
Jun 26 Javascript
基于JavaScript实现无缝滚动效果
Jul 21 Javascript
使用express搭建一个简单的查询服务器的方法
Feb 09 Javascript
Vue2.0中三种常用传值方式(父传子、子传父、非父子组件传值)
Aug 16 Javascript
vue项目中定义全局变量、函数的几种方法
Nov 08 Javascript
Vue实现渲染数据后控制滚动条位置(推荐)
Dec 09 Javascript
用JavaScript对JSON进行模式匹配(Part 1-设计)
Jul 17 #Javascript
关于flash遮盖div浮动层的解决方法
Jul 17 #Javascript
JQUERY获取form表单值的代码
Jul 17 #Javascript
jQuery+ajax实现顶一下,踩一下效果
Jul 17 #Javascript
flexigrid 类似ext grid的JS表格代码
Jul 17 #Javascript
基于JQuery的Pager分页器实现代码
Jul 17 #Javascript
基于jQuery的Spin Button自定义文本框数值自增或自减
Jul 17 #Javascript
You might like
PHP防注入安全代码
2008/04/09 PHP
PHP stristr() 函数(不区分大小写的字符串查找)
2010/06/03 PHP
php遍历类中包含的所有元素的方法
2015/05/12 PHP
php处理json格式数据经典案例总结
2016/05/19 PHP
Ucren Virtual Desktop V2.0
2006/11/07 Javascript
jquery ajax,ashx,json的用法总结
2014/02/12 Javascript
javascript的tab切换原理与效果实现方法
2015/01/10 Javascript
jQuery插件pagewalkthrough实现引导页效果
2015/07/05 Javascript
基于JavaScript实现TAB标签效果
2016/01/12 Javascript
Node.js获取前端ajax提交的request信息
2017/02/20 Javascript
jQuery插件HighCharts实现的2D面积图效果示例【附demo源码下载】
2017/03/15 Javascript
JS简单获取日期相差天数的方法
2017/04/24 Javascript
vue引入swiper插件的使用实例
2017/07/19 Javascript
JavaScript学习笔记之惰性函数示例详解
2017/08/27 Javascript
vue 引用自定义ttf、otf、在线字体的方法
2019/05/09 Javascript
vue读取本地的excel文件并显示在网页上方法示例
2019/05/29 Javascript
Python实现Linux中的du命令
2017/06/12 Python
对Python中的条件判断、循环以及循环的终止方法详解
2019/02/08 Python
PyTorch的深度学习入门之PyTorch安装和配置
2019/06/27 Python
使用pyshp包进行shapefile文件修改的例子
2019/12/06 Python
selenium+python配置chrome浏览器的选项的实现
2020/03/18 Python
python+selenium自动化实战携带cookies模拟登陆微博
2021/01/19 Python
波兰快递服务:Globkurier.pl
2019/11/08 全球购物
如何获得EntityManager
2014/02/09 面试题
旅游管理毕业生自荐书
2014/02/02 职场文书
小学敬老月活动方案
2014/02/11 职场文书
医院学雷锋活动策划方案
2014/02/15 职场文书
《凡卡》教学反思
2014/04/09 职场文书
材料化学专业求职信
2014/07/15 职场文书
合伙购房协议样本
2014/10/06 职场文书
2015年见习期工作总结
2014/12/12 职场文书
公司规章制度范本
2015/08/03 职场文书
简述Java中throw-throws异常抛出
2021/08/07 Java/Android
Redis中缓存穿透/击穿/雪崩问题和解决方法
2021/12/04 Redis
Python中的 Set 与 dict
2022/03/13 Python
Go语言grpc和protobuf
2022/04/13 Golang