用javascript编写反函数?
我今天在工作中遇到了一个情况,我需要编写我已经编写的函数的逆函数,但是我发现手动编写逆函数效率很低,因为我似乎会重复很多代码,如果我要更新原始函数,我必须用相应的更改来更新逆函数。我所说的函数如下所示:用javascript编写反函数?,javascript,function,lambda,functional-programming,Javascript,Function,Lambda,Functional Programming,我今天在工作中遇到了一个情况,我需要编写我已经编写的函数的逆函数,但是我发现手动编写逆函数效率很低,因为我似乎会重复很多代码,如果我要更新原始函数,我必须用相应的更改来更新逆函数。我所说的函数如下所示: var f = function(id, str) { if (id === 0) { return str.substring(0, 4) + " " + str.substring(4, 8); } else if (id === 1) { return str.su
var f = function(id, str) {
if (id === 0) {
return str.substring(0, 4) + " " + str.substring(4, 8);
} else if (id === 1) {
return str.substring(0, 3) + "/" + str.substring(3, 8);
} else if (id === 2) {
return str.substring(0, 4) + "-" + str.substring(4, 8);
} else if (id == 3) {
return str.substring(0, 3) + "," + str.substring(3, 8);
}
}
因此,例如
f(0,“ABCDEFGH”)
将返回“ABCD EFGH”
。我需要一个反向函数,它使用函数f(id,str)
从输出中获得输入。所以finverse(formattedStr)
应该返回对应输入的字典。例如,finverse(“ABCD-EFGH”)
应该返回{id:0,str:“ABCDEFGH”}
。是否可以利用现有函数f
来编写此逆函数,这样即使我要用额外的“else if”子句更新原始函数,也不必更新finverse
。换句话说,我不想用if语句手动构造finverse
,以将输出映射回输入,而是希望以某种方式操纵原始函数以得到一个逆函数。这在javascript中可能吗?真的没有办法让它完美地工作。这是不可能实现良好的速度特性。所以,我试着给你们两种解决这个问题的方法:
f()
中使用的规则将全局对象命名为fRules
然后,您可以在f()
中使用fRules
简单地查找具有所需id
的规则,并在fInverse
中迭代规则数组并查找好的规则。现在您不需要更改f()
,只需更改fRules()
f.toString()
获取函数文本,并将函数解析为抽象语法树。就像UglifyJs的内部功能一样。阅读更多。然后,必须根据函数语法树手动编写一些反转器。丑恶的想法通过稍微的重新分解,任务实际上相当简单。您不需要所有这些ifs,事实上,ifs的运行速度比对象属性查找慢,更不用说它们没有被封装在某个私有函数中 我们可以在没有任何流逻辑的情况下完成转换(1 in,1+out):
// replace all the IF logic with an externally-modifiable logic table:
f.lut=[ [4," "], [3,"/"], [4,"-"], [3,","] ]; //(id=index, 0=pos, 1=char)
// simplify f() using the table to make choices instead of conditionals:
function f(id, str) {
id = f.lut[id];
return str.substring(0, id[0]) + id[1] + str.substring(id[0], 8);
}
// use the same table in reverse to compose an inverse function:
function finverse(s){
return {
id: +f.lut.map(function(A,i){ return A[1]==s.split(/[\w]+/).filter(Boolean)[0] ?
String(i):
""
}).filter(Boolean)[0][0],
str: s.split(/[\W]+/).filter(Boolean).join('')
};
}
// first, test new version of f():
f(0, "ABCDEFGH") // ABCD EFGH
f(1, "ABCDEFGH") // ABC/DEFGH
f(2, "ABCDEFGH") // ABCD-EFGH
f(3, "ABCDEFGH") // ABC,DEFGH
// now, test the inverse:
finverse("ABCD EFGH") //{id:0, str:"ABCDEFGH"}
finverse("ABC/DEFGH") //{id:1, str:"ABCDEFGH"}
finverse("ABCD-EFGH") //{id:2, str:"ABCDEFGH"}
finverse("ABC,DEFGH") //{id:3, str:"ABCDEFGH"}
如果这不是您想要的,请告诉我们,我不是100%确定…我不知道
.filter(Boolean)
速记,很好。显然,这也适用于ES6中的箭头函数:.filter((x)=>!!.x)
。实际上也不需要将arg括在括号中:.filter(x=>!!.x)
@cssimsek:.filter(x=>x)
将实现与ES6中的.filter(Boolean)
相同的效果这很好,因此无需使用进行强制转换代码>;每次迭代时分配给x
的值隐式转换为其布尔值。Array.prototype.boolFilter=function(){return Array.prototype.filter.call(this,x=>x);}代码>从崇高到荒谬:pYou还可以使用计算机代数系统获得逆运算,因为一些JavaScript函数可以转换为数学表达式,反之亦然。
// replace all the IF logic with an externally-modifiable logic table:
f.lut=[ [4," "], [3,"/"], [4,"-"], [3,","] ]; //(id=index, 0=pos, 1=char)
// simplify f() using the table to make choices instead of conditionals:
function f(id, str) {
id = f.lut[id];
return str.substring(0, id[0]) + id[1] + str.substring(id[0], 8);
}
// use the same table in reverse to compose an inverse function:
function finverse(s){
return {
id: +f.lut.map(function(A,i){ return A[1]==s.split(/[\w]+/).filter(Boolean)[0] ?
String(i):
""
}).filter(Boolean)[0][0],
str: s.split(/[\W]+/).filter(Boolean).join('')
};
}
// first, test new version of f():
f(0, "ABCDEFGH") // ABCD EFGH
f(1, "ABCDEFGH") // ABC/DEFGH
f(2, "ABCDEFGH") // ABCD-EFGH
f(3, "ABCDEFGH") // ABC,DEFGH
// now, test the inverse:
finverse("ABCD EFGH") //{id:0, str:"ABCDEFGH"}
finverse("ABC/DEFGH") //{id:1, str:"ABCDEFGH"}
finverse("ABCD-EFGH") //{id:2, str:"ABCDEFGH"}
finverse("ABC,DEFGH") //{id:3, str:"ABCDEFGH"}