if else 和 switch && 递归
- if else 和 switch
一般来说,if-else 适用于判断两个离散的值或者判断几个不同的值域。如果判断多于两个离散值,switch
表达式将是更理想的选择。
如同 我们在写sql 总习惯把可以过滤掉更多的where 放在前面一样,当 if else 判断的离散值较多时也因该这么干。
二分搜索法:
if (value == 0){ //要优化的代码 return result0; } else if (value == 1){ return result1; } else if (value == 2){ return result2; } else if (value == 3){ return result3; } else if (value == 4){ return result4; } else if (value == 5){ return result5; } else if (value == 6){ return result6; } else if (value == 7){ return result7; } else if (value == 8){ return result8; } else if (value == 9){ return result9; } else { return result10; }
if (value < 6){ //二分搜索法 if (value < 3){ if (value == 0){ return result0; } else if (value == 1){ return result1; } else { return result2; } } else { if (value == 3){ return result3; } else if (value == 4){ return result4; } else { return result5; } } } else { if (value < 8){ if (value == 6){ return result6; } else { return result7; } } else { if (value == 8){ return result8; } else if (value == 9){ return result9; } else { return result10; } } }
代码很简单 ,效果却很明显.
查表法:
//define the array of results var results = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10] //return the correct result return results[value];
更加简单暴力。
- 递归
引用:
JavaScript引擎所支持的递归数量与 JavaScript调用栈大小直接相关。只有 Internet Explorer例外,它的
调用栈与可用系统内存相关,其他浏览器有固定的调用栈限制。大多数现代浏览器的调用栈尺寸比老式浏
览器要大(例如 Safari 2调用栈尺寸是 100)。图 4-2 显示出主流浏览器的调用栈大小。
关于调用栈溢出错误,最令人感兴趣的部分大概是:在某些浏览器中,他们的确是 JavaScript 错误,可
以用一个 try-catch 表达式捕获。异常类型因浏览器而不同。在 Firefox 中,它是一个 InternalError;在 Safari
和 Chrome 中,它是一个 RangeError;在 Internet Explorer中抛出一个一般性的 Error类型。(Opera 不抛出
错误;它终止 JavaScript引擎)。这使得我们能够在 JavaScript 中正确处理这些错误:
try {
recurse();
} catch (ex){
alert("Too much recursion!");
}
如果不管它,那么这些错误将像其他错误一样冒泡上传(在 Firefox中,它结束于 Firebug 和错误终端;
在 Safari/Chrome 中它显示在 JavaScript 终端上),只有 Internet Explorer例外。IE 不会显示一个 JavaScript
错误,但是会弹出一个提示堆栈溢出信息的对话框。
大多数调用栈错误与递归有关。常见的栈溢出原因是一个不正确的终止条件,所以定位模式
错误的第一步是验证终止条件。如果终止条件是正确的,那么算法包含了太多层递归,为了能够安全地在
浏览器中运行,应当改用迭代,制表,或两者兼而有之。
任何可以用递归实现的算法都可以用迭代实现。迭代算法通常包括几个不同的循环,分别对应算法过程
的不同方面,也会导致自己的性能为题。但是,使用优化的循环替代长时间运行的递归函数可以提高性能,
因为运行一个循环比反复调用一个函数的开销要低。
优化递归的方案 制表
一个经典的案例:
function factorial(n){ if (n == 0){ return 1; } else { return n * factorial(n-1); } }
var fact6 = factorial(6); //factorial 计算阶乘 var fact5 = factorial(5); var fact4 = factorial(4);
此代码生成三个阶乘结果,factorial()函数总共被调用了 18次。此代码中最糟糕的部分是,所有必要的
计算已经在第一行代码中执行过了。因为 6 的阶乘等于 6乘以 5 的阶乘,所以 5的阶乘被计算了两次。更
糟糕的是,4的阶乘被计算了三次。更为明智的方法是保存并重利用它们的计算结果,而不是每次都重新
计算整个函数。比如这样:
function memfactorial(n){ if (!memfactorial.cache){ memfactorial.cache = { "0": 1, "1": 1 }; } if (!memfactorial.cache.hasOwnProperty(n)){ memfactorial.cache[n] = n * memfactorial (n-1); } return memfactorial.cache[n]; }
var fact6 = memfactorial(6);
var fact5 = memfactorial(5);
var fact4 = memfactorial(4);
//总共只调用 memfactorial()函数八次
这样未免太过于繁琐,如果把制表的过程封装起来比如这样:
function memoize(fundamental, cache){ cache = cache || {}; var shell = function(arg){ if (!cache.hasOwnProperty(arg)){ cache[arg] = fundamental(arg); } return cache[arg]; }; return shell; }
//memoize the factorial function var memfactorial = memoize(factorial, { "0": 1, "1": 1 }); //call the new function var fact6 = memfactorial(6); var fact5 = memfactorial(5); var fact4 = memfactorial(4);
需要提醒的是:当一个通用制表函数存在显著性能问题时,最好在这些函数中人工实现制表法。
最后:运行的代码总量越大,使用这些策略所带来的性能提升就越明显。 代码全是copy书上的,所以强烈建议直接去看书而不是看我罗里吧嗦的几个字总结。
下一章将学习字符串和正则表达式很期待。