我使用pouchDb并查询数据库需要创建一个map函数(这是couchDB的标准做法)
此版本正常运作:
function (doc) {
if (doc.type) {
emit(doc.type)
}
}.toString()
,结果是:
"function mapFunction(doc) {
if (doc.type) {
emit(doc.type);
}
}"
但是,我试图将我的函数调用更加动态,因此我可以通过一个字段来构建map函数。考虑到这一点,我有一个名为field
的变量,我将我的地图功能更改为:
var field = '_id'
function (doc) {
if (doc[field]) {
emit(doc[field)
}
}.toString()
问题是,生成的字符串是这样的:
"function mapFunction(doc) {
if (doc[field]) {
emit(doc[field]);
}
}"
但我需要它:
"function mapFunction(doc) {
if (doc['_id']) { //or doc._id (I don't mind)
emit(doc['_id']);
}
}"
有可能实现这个目标吗?
编辑:更糟糕的情况是,我把它写成一个字符串并按照这种方式进行,但更愿意将它作为一个可读的函数。
答案 0 :(得分:1)
也许是一个带有函数,变量名和值的生成器,并创建你想要的字符串。
像
这样的东西
function functionGenerator(func, variable, value){
var r = new RegExp(variable,'gi');
return func.toString().replace(r, value);
}
function mapFunction(doc) {
if (doc[field]) {
emit(doc[field]);
}
}
var map = functionGenerator(mapFunction, 'field','\'_id\'');
console.log(map);
答案 1 :(得分:1)
您可以在Function原型上定义一个执行toString
的新方法,但允许以对象格式传递变量集合 - 其中每个键都是要使用的变量。这些变量在函数的字符串表示中注入,在函数体打开后用var
声明。
每个变量都获得其原始值的JSON表示。当然,这有一些限制,因为并非所有值都可以表示为JSON(循环引用,带方法的对象,等等)。但它肯定适用于原始值,如字符串:
Function.prototype.toStringWith = function(vars) {
return this.toString().replace(/(\)\s*{)/,
'$1\n var ' + Object.keys(vars)
.map( key => key + ' = ' + JSON.stringify(vars[key]) )
.join(',\n ') + ';');
}
// Demo
var field = '_id'
var s = function mapFunction(doc) {
if (doc[field]) {
emit(doc[field])
}
}.toStringWith({field}); // ES6 shortcut notation
console.log(s);

如果您有更多功能需要的变量"知道",如size
,weight
,brand
,那么您拨打.toStringWith({field, size, weight, brand})
,等等。
注意:在函数源中搜索变量名称并将其替换为文字值的解决方案需要小心:变量名称可能出现在带引号的字符串中(单引号,双引号之间)或模板文字,或者是更大名称的一部分,不应该被替换。
答案 2 :(得分:0)
我认为最简单的解决方案是简单的正则表达式。
var field = '_id';
var a = function (doc) {
if (doc[field]) {
emit(doc[field])
}
}.toString();
console.log(a.replace(/field/gi, field));

答案 3 :(得分:0)
正如我所评论的那样,因为你需要解析并重新生成这个字符串化的函数。我无法相信插件会强迫某人对函数进行字符串化。
由于从field
到__id
(由于其他标识符等)替换广泛,因此您只能使用其初始值重新声明此field
字符串化函数中的值(在顶部指定其值)。
不相关的建议:
(提醒: var
语句在整个范围内声明一个变量,因此也可以在var
语句出现之前分配变量。)
//////////////////////////////////////////////
//////////////// References //////////////////
//////////////////////////////////////////////
var _stringify = JSON.stringify
//////////////////////////////////////////////
//////////////// Variables //////////////////
//////////////////////////////////////////////
var field = '__id'
/* Store the variables to be copied in the top here */
var locals = { field: field }
/* String to contain the variables */
var stringified_locals = '',
// thanks to this var length notation
// we'll separate the variables by commas
len = 0
/* Calculate the length of vars */
for (let prop in locals)
++len
/* Also useful for the variable separation */
i = 0; var i
/* Only declare the 'var' statement if there's at least
* ONE var */
if (len)
stringified_locals = 'var '
/* Now generate the string of variables */
for (let prop in locals) {
let value = _stringify(locals[prop])
stringified_locals += prop + ' = ' + value
/* Add comma separator if neccessary */
if (i++ < (len - 1))
stringified_locals += ', '
}
/* And the complete stringified function */
stringified_locals + '\r\n' +
(function (doc) {
if (doc.type) {
emit(doc.type)
}
}).toString()
得到了结果:
`var field = "__id"
function (doc) {
if (doc.type) {
emit(doc.type)
}
}`
答案 4 :(得分:0)
你可以这样做:
"(function() {\n" +
"var field = " + JSON.stringify(field) + ";\n" +
"return " + mapFunction.toString() + ";" +
"})()"
警告:在极少数情况下,JSON.stringify
不会产生有效的javascript。我不确切知道这些案件是什么,或者恶意用户是否有可能以某种方式利用它们。 (你相信谁提供field
的价值?)