最近要做数据处理,自定义了一些数据结构,比如Mat,Vector,Point之类的,对于加减乘除之类的四则运算还要重复定义,代码显得不是很直观,javascript没有运算符重载这个像C++、C#之类的功能的确令人不爽,于是想“曲线救国”,自动将翻译代码实现运算符重载,实现思路其实很简单,就是编写一个解释器,将代码编译。例如:
S = A + B (B - C.fun())/2 + D
翻译成
`S = replace(replace(A, '+', replace(replace(B,'',(replace(B,'-',C.fun())))),'/',2),'+',D)`
在replace函数中我们调用对象相应的运算符函数,replace函数代码如下:
/**
* 转换方法
* @param a
* @param op
* @param b
* @returns {*}
* @private
*/
export function __replace__(a,op,b){
if(typeof(a) != 'object' && typeof(b) != 'object'){
return new Function('a','b','return a' + op + 'b')(a,b)
}
if(!Object.getPrototypeOf(a).isPrototypeOf(b)
&& Object.getPrototypeOf(b).isPrototypeOf(a)){
throw '不同类型的对象不能使用四则运算'
}
let target = null
if (Object.getPrototypeOf(a).isPrototypeOf(b)) {
target = new Function('return ' + b.__proto__.constructor.name)()
}
if (Object.getPrototypeOf(b).isPrototypeOf(a)) {
target = new Function('return ' + a.__proto__.constructor.name)()
}
if (op == '+') {
if (target.__add__ != undefined) {
return target.__add__(a, b)
}else {
throw target.toString() +'\n未定义__add__方法'
}
}else if(op == '-') {
if (target.__plus__ != undefined) {
return target.__plus__(a, b)
}else {
throw target.toString() + '\n未定义__plus__方法'
}
}else if(op == '*') {
if (target.__multiply__ != undefined) {
return target.__multiply__(a, b)
}else {
throw target.toString() + '\n未定义__multiply__方法'
}
} else if (op == '/') {
if (target.__divide__ != undefined) {
return target.__divide__(a, b)
}else {
throw target.toString() + '\n未定义__divide__方法'
}
} else if (op == '%') {
if (target.__mod__ != undefined) {
return target.__mod__(a, b)
}else {
throw target.toString() + '\n未定义__mod__方法'
}
} else if(op == '.*') {
if (target.__dot_multiply__ != undefined) {
return target.__dot_multiply__(a, b)
}else {
throw target.toString() + '\n未定义__dot_multiply__方法'
}
} else if(op == './') {
if (target.__dot_divide__ != undefined) {
return target.__dot_divide__(a, b)
}else {
throw target.toString() + '\n未定义__dot_divide__方法'
}
} else if(op == '**') {
if (target.__power__ != undefined) {
return target.__power__(a, b)
}else {
throw target.toString() + '\n未定义__power__方法'
}
}else {
throw op + '运算符无法识别'
}
}
replace实现非常简单,不做过多解释,重要的部分是如何实现代码的编译。大学学习数据结构时四则运算的实现就是这翻译的基础,略微有些差异。简单描述一下流程:
1、分割表达式,提取变量和运算符获得元数组A
2、遍历元数组
如果元素是运算符加减乘除,则从堆栈中弹出上一个元素,转换为replace(last,操作符,
如果元素是‘)',则从堆栈中弹出元素,拼接直到遇到'(',并压入堆栈。这里需要注意‘('元素前是否为函数调用或replace,如果是函数调用或replace,则需要继续向前弹出数据,闭合replace函数的闭合。
如果是一般元素,则查看前一个元素是否replace,如果是,则需要拼接‘)'使得replace函数闭合,否则直接将元素压入栈。
3、将2步骤中得到的栈顺序组合就得到编译后的表达式。
依据上述流程,实现代码:
/**
* 表达式转换工具方法
* @param code
*/
export function translate (code) {
let data = []
let tmp_code = code.replace(/\s/g,'')
let tmp = []
let vari = tmp_code.split(/["]+[^"]*["]+|[']+[^']*[']+|\*\*|\+|-|\*|\/|\(|\)|\"]+[^"]*["]+|[']+[^']*[']+|\*\*|\+|-|\*|\/|\(|\)|\"htmlcode">
export default class OOkay {
constructor () {
let protos = Object.getOwnPropertyNames(Object.getPrototypeOf(this))
protos.forEach((proto, key, own) => {
if(proto != 'constructor'){
Object.defineProperty(this, proto, {
value:new Function(translate_block(proto, this[proto].toString())).call(this)
})
}
})
}
}
由上面可以看出,我们使用Object.defineProperty在构造器中重新定义了,translate_block是对整个代码块分割得到进行翻译,代码如下:
/**
* 类代码块转换工具
* @param name
* @param block
* @returns {string}
*/
export function translate_block (name , block) {
let codes = block.split('\n')
let reg = new RegExp('^' + name + '$')
console.log(reg.source)
codes[0] = codes[0].replace(name,'function')
for(let i = 1; i < codes.length; i++) {
if (codes[i].indexOf('//') != -1) {
codes[i] = codes[i].substring(0,codes[i].indexOf('//'))
}
if(/\*\*|\+|-|\*|\/|%|\.\/|\.\*/g.test(codes[i])){
if (codes[i].indexOf('return ') != -1) {
let ret_index = codes[i].indexOf('return ') + 7
codes[i] = codes[i].substring(0,ret_index) + translate(codes[i].substring(ret_index))
}else {
let eq_index = codes[i].indexOf('=') + 1
codes[i] = codes[i].substring(0,eq_index) + translate(codes[i].substring(eq_index))
}
}
}
return 'return ' + codes.join('\n')
}
对于新的类,我们只要继承OOkay类就可以在该类中使用运算符重载。对于继承自非OOkay类的,我们可以采用注入的方式,如下:
/**
* 非继承类的注入方法
* @param target
*/
static inject (target) {
let protos = Object.getOwnPropertyNames(Object.getPrototypeOf(target))
protos.forEach((proto, key, own) => {
if (proto != 'constructor') {
Object.defineProperty(target, proto, {
value:new Function(translate_block(proto, target[proto].toString())).call(target)
})
}
})
}
对于非类中的代码,我们需要一个容器,这里我采用了两种方式,一种以ookay脚本的方式使用,像这样
<script type='text/ookayscript'>
let a = a+b // a、b为对象实例
</script>
还有就是将代码作为参数传入__$$__方法,该方法编译代码并执行,如下:
static __$__(fn) {
if(!(fn instanceof Function)){
throw '参数错误'
}
(new Function(translate_block('function',fn.toString()))).call(window)()
}
这样就实现了运算符的重载
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]