用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 相关文章推荐
HTML中Select不用Disabled实现ReadOnly的效果
Apr 07 Javascript
dropdownlist之间的互相联动实现(显示与隐藏)
Nov 24 Javascript
jquery jqPlot API 中文使用教程(非常强大的图表工具)
Aug 15 Javascript
用按钮控制iframe显示的网页实现方法
Feb 04 Javascript
多个checkbox被选中时如何判断是否有自己想要的
Sep 22 Javascript
功能强大的Bootstrap组件(结合js)
Aug 03 Javascript
JS实现课堂随机点名和顺序点名
Mar 09 Javascript
Javascript实现时间倒计时效果
Jul 15 Javascript
基于es6三点运算符的使用方法(实例讲解)
Oct 12 Javascript
4 种滚动吸顶实现方式的比较
Apr 09 Javascript
微信小程序new Date()方法失效问题解决方法
Jul 29 Javascript
基于vue手写tree插件的那点事儿
Aug 20 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实现验证码功能
2006/10/09 PHP
WML,Apache,和 PHP 的介绍
2006/10/09 PHP
让codeigniter与swfupload整合的最佳解决方案
2014/06/12 PHP
动态创建的表格单元格中的事件实现代码
2008/12/30 Javascript
Jquery 动态添加按钮实现代码
2010/05/06 Javascript
限制textbox或textarea输入字符长度的JS代码
2013/10/16 Javascript
jQuery获得指定元素坐标的方法
2015/04/14 Javascript
学好js,这些js函数概念一定要知道【推荐】
2017/01/19 Javascript
js 输入框 正则表达式(菜鸟必看教程)
2017/02/19 Javascript
浅谈js函数三种定义方式 &amp; 四种调用方式 &amp; 调用顺序
2017/02/19 Javascript
VUE axios发送跨域请求需要注意的问题
2017/07/06 Javascript
详解Vue.js 作用域、slot用法(单个slot、具名slot)
2019/10/15 Javascript
微信小程序实现左侧滑动导航栏
2020/04/08 Javascript
vue实现在线预览pdf文件和下载(pdf.js)
2019/11/26 Javascript
Vue-resource安装过程及使用方法解析
2020/07/21 Javascript
[01:06:25]Secret vs Liquid 2018国际邀请赛淘汰赛BO3 第一场 8.25
2018/08/29 DOTA
Python编程实现二叉树及七种遍历方法详解
2017/06/02 Python
python函数中return后的语句一定不会执行吗?
2017/07/06 Python
Django数据库表反向生成实例解析
2018/02/06 Python
Python闭包函数定义与用法分析
2018/07/20 Python
Python二叉树的镜像转换实现方法示例
2019/03/06 Python
深入解析Python小白学习【操作列表】
2019/03/23 Python
python解析xml简单示例
2019/06/21 Python
对Tensorflow中Device实例的生成和管理详解
2020/02/04 Python
Django使用list对单个或者多个字段求values值实例
2020/03/31 Python
详解CSS3 用border写 空心三角箭头 (两种写法)
2017/09/29 HTML / CSS
HTML4和HTML5之间除了相似以外的10个主要不同
2012/12/13 HTML / CSS
La Redoute英国官网:法国时尚品牌
2017/04/27 全球购物
SIDESTEP荷兰:在线购买鞋子
2019/11/18 全球购物
如何写出高质量、高性能的MySQL查询
2014/11/17 面试题
机械电子工程毕业生自荐信
2013/11/23 职场文书
社会保险接收函
2014/01/12 职场文书
餐饮采购员岗位职责
2014/03/15 职场文书
工业自动化专业自荐信范文
2014/04/10 职场文书
2015年学校关工委工作总结
2015/04/03 职场文书
Django cookie和session的应用场景及如何使用
2021/04/29 Python