读高性能JavaScript编程 第四章 Conditionals

 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书上的,所以强烈建议直接去看书而不是看我罗里吧嗦的几个字总结。

下一章将学习字符串和正则表达式很期待。

posted @ 2016-12-08 19:36  zwsu  阅读(202)  评论(0编辑  收藏  举报