我正在创建模板选择器/轮盘Slack机器人。目标是向机器人发送消息并传递命令行之类的参数,并让它遍历JSON对象并随机选择符合条件的模板。用户也应该能够传递任何数量的参数。
示例:我使用此Roulette -s -i
向机器人发送消息-s
代表侧栏,-i
代表索引。因此,机器人需要找到一个既有侧边栏又有索引的模板。
这是我的JSON对象的示例:
{
name: "foo",
index: {
hasIndex: true
},
sidebar: {
hasSidebar: true
}
}
这是我的代码:
controller.hears(["roulette", "^pattern$"],["direct_message", "direct_mention", "mention"], function(bot,message) {
const data = require('./data.js');
const nodeList = []
const args = message.text.match(/-\w/g);
const obj = {
'-s': '.sidebar.hasSidebar',
'-i': '.index.hasIndex'
}
args.forEach(function(arg) {
var path = obj[arg];
// console.log(path) when passing arguments -s or -i
// the path variable correctly gives me .sidebar.hasSidebar, etc
data.forEach(function(node) {
// console.log(node) Gives me my data set
// console.log(node.path) This is the issue, it returns undefined.
if (node.path === true) {
nodeList.push(node.name)
}
});
});
});
我的问题是,如果node.path
正确地向我提供数据集,为什么我不能使用node
?难道我不能添加path
并完成路径以便forEach循环通过吗?相反,我得到了undefined
,我不明白为什么。
修改
我已更新了我的代码:
var nodeList = data.filter(function(node) {
return args.every(function(arg) {
return obj[arg](node);
});
});
const obj = {
'-s': function (node) { return node.sidebar.hasSidebar; },
'-i': function (node) { return node.index.hasIndex; },
};
data.forEach(function(node) {
args.forEach(function(arg) {
var pathTester = obj[arg];
if (pathTester(node)) {
nodeList.push(node.name)
}
});
});
1)我是否正确交换了循环?
2)我不太了解nodeList应该如何工作。
答案 0 :(得分:0)
当你写:
if (node.path === true)
...您正在寻找名为path
的媒体资源。这与您之前声明的变量path
无关。
使用此语法无法基于点分隔的字符串(如'.sidebar.hasSidebar'
)查找动态属性链。您必须致电eval()
才能实现这一目标,如下所示:
if (eval('node' + path) === true)
这样做有效,但由于eval
名声不好,我建议您使用函数而不是字符串来定义obj
,如下所示:
const obj = {
'-s': function (node) { return node.sidebar.hasSidebar; },
'-i': function (node) { return node.index.hasIndex; },
};
...然后检索并调用函数:
args.forEach(function(arg) {
var pathTester = obj[arg];
data.forEach(function(node) {
if (pathTester(node)) {
nodeList.push(node.name);
}
});
});
现在,上面回答了这个问题,但正如你提到的那样:
示例:我使用此
Roulette -s -i
向机器人发送消息-s
代表侧栏,-i
代表索引。因此,机器人需要找到一个既有侧边栏又有索引的模板。
...我需要指出,即使只有一个条件为真,您当前的代码也会将节点推送到节点列表,并且可能会多次推送相同的节点。
如果您希望仅在所有条件都为真时添加节点,那么交换您的循环并确保只有当(然后)内部循环为所有参数返回true时才添加节点。
同时我建议使用every
和filter
函数:
var nodeList = data.filter(function(node) {
return args.every(function(arg) {
return obj[arg](node);
});
});
请注意,此会替换您拥有的forEach
循环。完整的代码如下所示:
controller.hears(["roulette", "^pattern$"],["direct_message", "direct_mention", "mention"], function(bot,message) {
const data = require('./data.js');
const args = message.text.match(/-\w/g);
const obj = {
'-s': function (node) { return node.sidebar.hasSidebar; },
'-i': function (node) { return node.index.hasIndex; },
};
var nodeList = data.filter(function(node) {
return args.every(function(arg) {
return obj[arg](node);
});
});
});
filter
和every
以上是filter
和every
的强大功能。如果没有这些方法,代码可能如下所示:
var nodeList = [];
data.forEach(function(node) {
// Check if this node should be added
var addNode = true; // start positive...
args.forEach(function(arg) {
var pathTester = obj[arg];
if (pathTester(node) !== true) {
// if not all paths are true, don't add the node
addNode = false;
}
});
if (addNode) {
nodeList.push(node);
}
});
true
编写这样的代码时:
if (property === true)
... 和你肯定知道属性总是一个布尔值(如果已定义),那么你可以这样写:
if (property)
这是因为if
语句需要一些评估为布尔值的语句。但如果 property 已经是布尔值,则无需与true
进行比较。 属性有三种可能性。它是:
undefined
false
true
当这三个值中的一个是if
表达式时,只有最后一个true
将成为if
条件true
。 undefined
被视为虚假价值。
但是,如果属性也可以是非布尔值,如数字,字符串或对象,并且您只想响应true
的确切值(不是任何值)其他值),那么做需要像=== true
那样进行测试。没有它,非零数值,非空字符串和对象将通过测试。