如果您的“做某事”具有不同值的相似形式,则可以将值放入映射中并使用字符串作为键。例如,假设您必须处理许多具有不同长度单位的数字,并且您希望将它们全部转换为米:
var conversionToMeters = {
"inch": 0.0254,
"inches": 0.0254,
"foot": 0.3048,
"feet": 0.3048,
"cubit": 0.4572,
"cubits": 0.4572,
"yard": 0.9144,
"yards": 0.9144,
"kilometer": 1000,
"kilometers": 1000,
"mile": 1609.344,
"miles": 1609.344,
"lightyear": 9.46e15,
"lightyears": 9.46e15,
"parsec": 3.09e16,
"parsecs": 3.09e16,
}
(为简洁起见,省略了缩写(如“km”)和国际拼写(如“kilometres”)。)您可以提前准备该地图以避免创建开销。现在,给定一个变量length
,例如length = "80 miles"
,您可以执行以下操作:
var magnitude = length.replace(/[\D]/g, "");
var unit = length.replace(/[\d\s]/g, "");
var lengthInMeters = magnitude * conversionToMeters[unit];
alert(lengthInMeters + " meters"); // Ta-da!
如果您的“做某事”不共享公共代码,您仍然可以使用地图,但它将是功能地图:
var actions = {
"eat": function() {
if (spareFood > 0) {
spareFood--;
energy += 10;
health++;
alert("Yum!");
}
},
"walk": function() {
if (energy > 0) energy--;
// ...
},
"attack": function() {
if (energy > 0) {
if (Math.random() < 0.25) {
health--;
alert("Ouch!");
}
energy--;
}
},
// ...
};
这是一个有点愚蠢的例子,但我希望它能解释基本思想。这些操作同样可以是 XML 标签,或者虚拟机中 CPU 指令的名称,或者有特殊运输要求的产品名称,等等。一旦你得到你的action
变量,执行它就像这样简单:
actions[action]();
地图不是做这种事情的唯一方法。您的原始 if/else 示例可以通过将 if 嵌套在其他 if 中轻松优化,这些 if旨在快速消除大多数候选字符串。
您分支的标准将取决于您正在使用的确切字符串。它可以是字符串的长度,也可以是第一个字母,或者是几个最显着的字母:
if (str.length === 3) {
// test all length 3 strings here
if (str === strA) doSomething();
else if (str == strB) doSomething();
} else if (str.length === 4) {
// test all length 4 strings here
if (str === strC) doSomething();
else if (str === strD) doSomething();
}
或者:
var first = str[0]; // first character
if (first >= "0" && first <= "9") {
// test all strings that start with digits here
if (first >= "a" && first <= "l") {
// test all strings that start with letters
// in the first half of the alphabet here
} else if (first >= "m" && first <= "z") {
// test all strings that start with letters
// in the latter half of the alphabet here
}
您可以将这些类型的测试相互嵌套到任何适合筛选您正在使用的特定字符串的程度。这是一种展开的二分搜索,尽管您所依据的条件不必将候选字符串精确地分成两组。
此外,当您使用这样的 if/elseif 时,通常值得按频率降序排列字符串。即,首先测试发生最多的那些。如果只有几个字符串构成了大部分数据,请将它们拉到顶部,甚至将它们放在任何基于长度或首字母的预测试之外。
您必须决定是否值得做这些事情:如果您将这些技术发挥到极致,您可能会获得微小的额外性能优势,但会牺牲可读性和可维护性。
PS 我不太了解 JavaScript,无法确切知道这些技术将如何执行,但我在 Java 中做过类似的事情。在 Java 中,当“做某事”需要不同的值但可以使用相同的代码时,映射方法是无与伦比的。在另一个程序中,我需要switch
对一个整数值执行大约 400 个不同的操作(这太糟糕了)。HotSpot 客户端虚拟机有一个糟糕的低效实现switch
那个语句简直就是一大堆 elseif,而且太慢了。一组函数(从技术上讲是具有重写虚方法的对象)更快,但是与每个操作的简单性相比,函数调用开销太大了。在这种情况下,我发现混合二元四元搜索是有效的。这意味着:外部测试是将输入值平均分为两组的 if/else。这些被嵌套,直到内部组中只剩下四个可能的值。然后我使用了 if/elseif/elseif/else 来区分剩余的四个值。由于这很长,我写了一些代码来为我编写它,但对于这个特定的应用程序来说仍然值得付出努力。
PPS 上面有一种方法我跳过了,但为了完整起见,我将其包括在内:如果您的字符串很少需要更改,您可以使用完美的散列函数。有一些实用程序可以为您设计这些功能:只需为它们提供所有字符串的列表。一个完美的哈希函数会从一个字符串中计算出一个整数哈希码,并保证你的集合中没有两个字符串具有相同的哈希码。然后,您可以使用整数哈希码在数组中查找操作。它对解析编程语言的关键字等事情很有帮助。在更接近金属的语言中它可以更快,但在 JavaScript 中我怀疑它不值得。我提一下以防万一。