JavaScript中的模式匹配
JavaScript中的模式匹配
模式是用于转换输入数据的规则。 以将数据与一个或多个逻辑结构进行比较,将数据分解为各个构成部分,或以各种方式从数据中提取信息。
安装
JavaScript已经实现模式匹配解构功能,没有实现模式匹配过滤功能。用模式来控制程序流,可以编写更加声明性,更加模块化的代码,请安装structural-comparison
以支持此功能。structural-comparison
是一个函数库。包括函数式编程的常用函数。开源于GitHub,见xp44mm/structural-comparison
仓库。
npm i structural-comparison
用法:
import { match } from 'structural-comparison'
match: (pattern:string) -> (input:any) -> boolean
match
是一个柯里函数,模式参数是一个字符串,输入参数可以是任何值,当匹配成功返回真,否则返回假。
示例
模式匹配分为字面量模式,类型测试模式,标识符模式,数组模式,对象模式,OR模式,以及它们的组合嵌套模式。
字面量模式
测试原子值。模式是基元值字面量,支持JSON中的所有字面量。包括null
,布尔值,数字值,字符串值。字符串是JSON的双引号格式。不支持undefined
,NaN
,Infinity
等非JSON值。
test("value NULL", () => {
let y = match('null')
expect(y(null)).toEqual(true)
expect(y(3)).toEqual(false)
})
这里y
函数等价于:
let y = input => input === null
输入对象相等(===
)于模式。
其他字面量模式的示例:
test("value boolean", () => {
let y = match('false')
let v = y(false)
let w = y(3)
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("value number", () => {
let y = match('123')
let v = y(123)
let w = y(3)
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("value quote", () => {
let y = match('""')
let v = y('')
let w = y(3)
expect(v).toEqual(true)
expect(w).toEqual(false)
})
类型模式
测试数据的数据类型。模式是数据类型的名称,不带双引号。包括boolean
,string
,number
,function
。
test("value TYPE", () => {
let y = match('number')
let v = y(5)
let w = y(true)
expect(v).toEqual(true)
expect(w).toEqual(false)
})
这里y
函数等价于:
let y = input => typeof input === 'number'
输入对象typeof
值等于模式中的数据类型名称。
标识符模式
是一个合法的JavaScript标识符,除了标识符不包括$
字符,但是不能是类型名称。模式中的标识符和类型名都是区分大小写的,这和JavaScript语法一致。标识符模式始终成功匹配任何一个值。
test("value ID", () => {
let y = match('x')
let v = y(5)
let w = y({})
expect(v).toEqual(true)
expect(w).toEqual(true)
})
通配模式虽然是标识符,但实际上,是一个弃元(discard),弃元表示一个我们完全用不上的数值。仅用于占位。相同的名称不会引起名称冲突。
数组模式
匹配一个数组。数组匹配根据数组元素长度分为长度严格匹配,和最短长度匹配。严格匹配示例:
test("value array", () => {
let y = match('[]')
let v = y([])
let w = y({})
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("array elements", () => {
let input = '[1]'
let y = match(input)
let v = y([1])
let w = y([{ x: 0 }])
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("elements elements value", () => {
let input = '[1, 2]'
let y = match(input)
let v = y([1, 2])
let w = y([null, 1])
expect(v).toEqual(true)
expect(w).toEqual(false)
})
如果有省略号表示可以匹配任何更多的数组元素。最短长度匹配:
test("array ELLIPSIS", () => {
let input = '[...]'
let y = match(input)
let v = y([1])
let w = y({})
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("array elements ELLIPSIS", () => {
let input = '[null, ...]'
let y = match(input)
let v = y([null])
let w = y([null, 0])
let p = y([0])
expect(v).toEqual(true)
expect(w).toEqual(true)
expect(p).toEqual(false)
})
test("array ELLIPSIS elements", () => {
let input = '[ ..., null]'
let y = match(input)
let v = y([null])
let w = y([0, null])
let p = y([null, 0])
expect(v).toEqual(true)
expect(w).toEqual(true)
expect(p).toEqual(false)
})
test("array elements ELLIPSIS elements", () => {
let y = match('[1,2,...,4,5]')
let v = y([1,2,3,4,5])
let w = y([1,2,3])
expect(v).toEqual(true)
expect(w).toEqual(false)
})
数组语法不支持洞(连续逗号),不支持尾逗号。不支持迭代器。
数组模式大致编译成如下:
let y = input => Array.isArray(input) && every elements matched
对象模式
匹配一个对象。如果有省略号表示对象可以有任何更多的属性。只检测自有属性,忽略原型中的属性。对象语法支持特殊标识属性,快捷属性,属性不支持尾逗号。
test("value object", () => {
let input = '{}'
let y = match(input)
let v = y({})
let w = y({ x: 0 })
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("object ELLIPSIS", () => {
let input = '{...}'
let y = match(input)
let v = y({})
let w = y({ x: 0 })
let p = y([])
expect(v).toEqual(true)
expect(w).toEqual(true)
expect(p).toEqual(false)
})
test("object properties", () => {
let input = '{x}'
let y = match(input)
let v = y({ x: 0 })
let w = y([null, 1])
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("object properties ELLIPSIS", () => {
let input = '{x,...}'
let y = match(input)
let v = y({ x: 0, y: 1 })
let w = y({})
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("properties properties prop", () => {
let input = '{x,y}'
let y = match(input)
let v = y({ x: 0, y: 1 })
let w = y({})
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("prop key value", () => {
let input = '{x:null}'
let y = match(input)
let v = y({ x: null })
let w = y([null, 1])
expect(v).toEqual(true)
expect(w).toEqual(false)
})
test("key QUOTE", () => {
let input = '{"1":null}'
let y = match(input)
let v = y({ '1': null })
let w = y([null, 1])
expect(v).toEqual(true)
expect(w).toEqual(false)
})
对象模式编译成:
let y = obj => typeof obj === 'object' && obj && !Array.isArray(obj) && every props matched
OR模式
或模式,用一个竖杠符号连接两个模式,两个模式中任何一个模式成功即整体匹配成功。
test("OR", () => {
let y = match('string|{...}')
let a = y('')
let b = y({})
let c = y([])
let d = y(x => x)
expect(a).toEqual(true)
expect(b).toEqual(true)
expect(c).toEqual(false)
expect(d).toEqual(false)
})
OR模式编译成:
let y = obj => pat1 matched || pat2 matched
嵌套模式。匹配任意深度数据结构。
memoize解析的结果
上面的代码示例都用match(pattern)
来缓存,但是实际上,我们常用if else
条件选择语句来和模式匹配连用。
let y = x => {
if (match('[...]')(x)) console.log('[]')
else if (match('{...}')(x)) console.log('{}')
else if (match('string')(x)) console.log('string')
}
y([1]) // print []
这个是没有缓存的程序,每次调用y函数都会重新解析模式,对性能造成负面冲击。所以,我们需要缓存。
let arr = match('[...]')
let obj = match('{...}')
let str = match('string')
let y = x => {
if (arr(x)) console.log('[]')
else if (obj(x)) console.log('{}')
else if (str(x)) console.log('string')
}
y([1]) // print []
上面程序成功解决了性能问题,避免重复解析,但是引入中间变量导致代码复杂难懂。我们使用另一种解决方案。
import { match, cond } from 'structural-comparison'
let y = cond([
[match('[...]'), x => { console.log('[]') }],
[match('{...}'), x => { console.log('{}') }],
[match('string'), x => { console.log('string') }],
x => {
console.log('no matched!')
}
])
y([1]) // print []
y({}) // print {}
y(1) // print no matched!
cond
函数是一个返回函数的组合子,用来模拟if else
语句。它接受一个数组,数组的每个元素代表条件语句的一个分支。分支分为两种形式,第一种是断言函数,和行为函数组成的数组,当断言为真时,执行并返回行为,断言为假时跳过行为函数,执行下一分支。第二种是一个函数,当函数为真时,返回函数的返回值,当函数为假时,丢弃函数返回值,执行下一分支。cond
函数依次执行每个分支,返回第一个为真的分支结果为整体的结果。忽略其后所有分支。
JavaScript中的模式匹配的更多相关文章
- JavaScript 中的数据类型
Javascript中的数据类型有以下几种情况: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Function,Date,Ar ...
- javascript中的正则表达式学习
一.前言 关于正则表达式自身的语法这里不做过多介绍(详情可参见http://www.php100.com/manual/unze.html),这里仅仅解释javascript中和正则表达式相关的几个方 ...
- javascript中正则表达式的基础语法
× 目录 [1]定义 [2]特点 [3]元字符[4]转义字符[5]字符组[6]量词[7]括号[8]选择[9]断言[10]模式[11]优先级[12]局限性 前面的话 正则表达式在人们的印象中可能是一堆无 ...
- 转载 javascript中的正则表达式总结 一
定义正则表达式的方法 定义正则表达式的方法有两种:构造函数定义和正则表达式直接量定义.例如: var reg1 = new RegExp('\d{5, 11}'); // 通过构造函数定义 var r ...
- js学习笔记----JavaScript中DOM扩展的那些事
什么都不说,先上总结的图~ Selectors API(选择符API) querySelector()方法 接收一个css选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null ...
- C++、Java、JavaScript中的正则表达式
C++(VS2013编译器):http://msdn.microsoft.com/zh-cn/library/bb982727.aspx#grammarsummary Java: ...
- JavaScript中登录名的正则表达式及解析(0基础)
简言 在JavaScript中,经常会用到正则表达式来进行模式匹配.例如,登录名验证,密码强度验证,字符串查找或替换等操作.现在就开始吧,零基础写出你的第一个正则表达式! 在做用户注册时,都会用到登录 ...
- 精通 JavaScript中的正则表达式
精通 JS正则表达式 (精通?标题党 ) 正则表达式可以: •测试字符串的某个模式.例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式.这称为数据有效性验证 ...
- javascript中字符串对象常用的方法和属性
前言 字符串是一种非常重要的数据类型,在Java等面向对象编程语言中,它代表对象类型,而在javascript中它却是一种基本数据类型,在开发的领域中,我们经常会碰到,无论是前端还是后台.比如后台验证 ...
随机推荐
- JS 之 每日一题 之 算法 ( 有多少小于当前数字的数字 )
给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目. 换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 ...
- Dockerfile自动化制作镜像
1.创建Dockerfile文件:vim Dockerfile 2.Dockerfile的编写内容如下: 3.开始制作镜像 制作命令: docker build -t 镜像名:版本号 4.查看已经做好 ...
- JS_DOM操作之操作标签
<标签名 属性1="属性值1" 属性2="属性值2"-->文本</标签名> 1 - 文本操作 <div class="c ...
- JS005. 拷贝引用数据类型Array使其指向不同堆的解决方案
一个很常见的语法问题,但专注实现需求时经常会忘记去避免,导致最终问题的出现,再花时间排查.为此专门整理一篇解决方法的博客,也加强一下自己的记忆. TAG: JSON.parse() JSON.stri ...
- session案例之验证码
一.需求分析 其中,一张图片就是一个单独的请求: 一个验证验证码的Servlet,还有一个验证用户名和密码的Servlet,两次都可能有错误信息返回到前端页面,所以前面页面要从request域中获取返 ...
- Xilinx约束学习笔记(三)—— 时序概念
3. 时序概念 发现对于时序基础的介绍这一块,Intel 的文档竟然要比 Xilinx 的详细,因此引用了很多 Intel 的文档内容. 3.1 术语 发送沿(launch edge),指用来发送数据 ...
- Prometheus 2.21.0 新特性
Prometheus 2.21.0 现在(2020.09.11)已经发布,在上个月的 2.20.0 之后又进行了很多的修复和改进. 这个版本使用了 Go 1.15 进行编译,不赞成在TLS证书验证中使 ...
- 关于vue-cli的安装
(一):*安装 vue-cli 参考: https://cn.vuejs.org/v2/guide/installation.html https://github.com/vuejs/vue-cli ...
- 【转载】flag标志什么?哦,它标志代码馊了
几乎每次在代码中发现flag变量,我总是能嗅到一股馊味.不管你闻没闻到,反正我闻到了. 在代码中,flag通常作为标志变量的名字.但问题在于,不是所有的问题或代码都需要使用这种标志变量,更不是使用标志 ...
- 面试必问:Java 垃圾回收机制
摘要:垃圾回收机制是守护线程的最佳示例,因为它始终在后台运行. 本文分享自华为云社区<一文带你了解Java 中的垃圾回收机制>,作者:海拥. 介绍 在 C/C++ 中,程序员负责对象的创建 ...