高性能JavaScript循环语句和条件语句

一、循环语句
众所周知,常用的循环语句有for、while、do-while以及for-in,forEach。除了for-in和forEach性能略低外,平时我们对前三者的选择更多的是基于需求而非性能考虑,今天我们就对它们各自的性能做个测试,告诉我们最极端的情况下还能做哪些优化。

首先我们来谈谈为何for-in和forEach会比其他的慢。for-in一般是用在对象属性名的遍历上的,由于每次迭代操作会同时搜索实例本身的属性以及原型链上的属性,所以效率肯定低下;而forEach是基于函数的迭代(需要特别注意的是所有版本的ie都不支持,如果需要可以用JQuery等库),对每个数组项调用外部方法所带来的开销是速度慢的主要原因。

接着我们看看每次迭代中for、while以及do-while都做了什么。

var length = items.length;
for(var i = 0; i < length; i++)
 process(items[i]);

var j = 0;
while(j < length)
 process(items[j++]);

var k = 0;
do {
 process(items[k++]);
} while(k < length);

上面的每个循环中,每次运行循环体时都会产生这样的操作:

  • 一次控制条件中的数值大小比较(i < length)
  • 一次控制条件结果是否为true的比较(i < length === true)
  • 一次自增操作(i++)
  • 一次数组查找(items[i])
  • 一次函数调用process(items[i])

我们可以通过颠倒数组的顺序来提高循环性能:

for(var i = items.length; i--; )
 process(items[i]);

var j = items.length;
while(j--)
 process(items[j]);

var k = items.length - 1;
do {
 process(items[k]);
} while(k--);

本例中使用了倒序循环,并把减法操作整合在循环条件中。现在每个控制条件只是简单地与0比较。控制条件与true值比较,任何非零数会自动转换为true,而零值等同于false。实际上,控制条件从两个比较(迭代数少于总数吗?它是true吗?)减少到一次比较(它是true吗?)。每次迭代从两次比较减少到一次,进一步提高了循环速度。

性能测试:

那么事实真的如此吗?真金不怕浏览器验。测试代码很简单,针对不同的8种情况封装了8个函数(不加定时器firefox下无法打印profiles信息,原因不明):

// init array
var a = [];
var length = 10;
for(var i = 0; i < length; i++)
 a[i] = 1;

function for_in() {
 var sum = 0;
 for(var i in a)
  sum += a[i];
}

function for_each() {
 var sum = 0;
 a.forEach(function(value, index, array) {
  sum += value;
 });
}

function for_normal() {
 var sum = 0;
 for(var i = 0; i < length; i++)
  sum += a[i];
}

function for_reverse() {
 var sum = 0;
 for(var i = length; i--; )
  sum += a[i];
}

function while_normal() {
 var sum = 0;
 var i = 0;
 while(i < length)
  sum += a[i++];
}

function while_reverse() {
 var sum = 0;
 var i = length;
 while(i--)
  sum += a[i];
}

function do_while_normal() {
 var sum = 0;
 var i = 0;
 do {
  sum += a[i++];
 } while(i < length);
}

function do_while_reverse() {
 var sum = 0;
 var i = length - 1;
 do {
  sum += a[i];
 } while(i--);
}

setTimeout(function() {
 console.profile();
 for_in();
 for_each();
 for_normal();  
 for_reverse();
 while_normal();
 while_reverse();
 do_while_normal();
 do_while_reverse();
 console.profileEnd();
}, 1000);

当数组长度为100时,我们发现firefox下的结果确实和预料的相似:for-each和for-in效率低下,倒序比正序效率略微提升。(chrome下的profiles由于时间太短不显示)

当数据量达到100w时,firefox和chrome下的结果都如人所愿,但是也略微有所不同。ff下的for-in表现地比for-each好,而chrome下for-in表现糟糕,直接提出了警告。而倒序迭代虽然性能略微有所提升,但是提升的不是很多,且降低了代码阅读性。

小结:

  • 倒序迭代确实能略微提升代码性能,但是牺牲了代码可读性,除非追求极端性能优化情况下不然没必要用
  • 遍历数组能用普通的循环就不要用for-in和for-each

二、条件语句
常见的条件语句有if-else和switch-case,那么什么时候用if-else,什么时候用switch-case语句呢?

我们先来看个简单的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;
}

最坏的情况下(value=10)我们可能要做10次判断才能返回正确的结果,那么我们怎么优化这段代码呢?一个显而易见的优化策略是将最可能的取值提前判断,比如value最可能等于5或者10,那么将这两条判断提前。但是通常情况下我们并不知道(最可能的选择),这时我们可以采取二叉树查找策略进行性能优化。

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;
    }
  }
}

这样优化后我们最多进行4次判断即可,大大提高了代码的性能。这样的优化思想有点类似二分查找,和二分查找相似的是,只有value值是连续的数字时才能进行这样的优化。但是代码这样写的话不利于维护,如果要增加一个条件,或者多个条件,就要重写很多代码,这时switch-case语句就有了用武之地。

将以上代码用switch-case语句重写:

switch(value){
  case 0:
    return result0;
  case 1:
    return result1;
  case 2:
    return result2;
  case 3:
    return result3;
  case 4:
    return result4;
  case 5:
    return result5;
  case 6:
    return result6;
  case 7:
    return result7;
  case 8:
    return result8;
  case 9:
    return result9;
  default:
    return result10;
}

swtich-case语句让代码显得可读性更强,而且swtich-case语句还有一个好处是如果多个value值返回同一个结果,就不用重写return那部分的代码。一般来说,当case数达到一定数量时,swtich-case语句的效率是比if-else高的,因为switch-case采用了branch table(分支表)索引来进行优化,当然各浏览器的优化程度也不一样。

除了if-else和swtich-case外,我们还可以采用查找表。

var results = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10];

//return the correct result
return results[value];

当数据量很大的时候,查找表的效率通常要比if-else语句和swtich-case语句高,查找表能用数字和字符串作为索引,而如果是字符串的情况下,最好用对象来代替数组。当然查找表的使用是有局限性的,每个case对应的结果只能是一个取值而不能是一系列的操作。

小结:

  • 当只有两个case或者case的value取值是一段连续的数字的时候,我们可以选择if-else语句
  • 当有3~10个case数并且case的value取值非线性的时候,我们可以选择switch-case语句
  • 当case数达到10个以上并且每次的结果只是一个取值而不是额外的JavaScript语句的时候,我们可以选择查找表

以上就是本文的全部内容,希望对大家的学习有所帮助。

(0)

相关推荐

  • Javascript简写条件语句(推荐)

    经常在各处牛人的代码中看到许多简写的条件表达语句,看了一些介绍这方面的文章,觉得3 ways 2 say if这篇文章(http://www.thomasfrank.se/3_ways_2_say_if.html)还不错.在这篇文章中作者对传统的if...else....?:.&&/||三种条件表达的写法的特点及用处进行了总结归纳,简述如下: 1. if...else结构 // Set r to 0 or 1 var r= Math.floor(2*Math.random()) // Se

  • Javascript基础教程之if条件语句

    if 是常用语法之一,其格式如下 if(coditon) statement1 (else statement2) 其中,coditon可以是任何表达式,甚至不比是真正的布尔值,因为JavaScript会将其自动转化为布尔值. 如果条件执行结果为true,则执行statement1,如果条件为false,则执行结果statment2,(如果statement2存在,则else不是必须的) 每个条件语句可以是单行代码,也可以是代码块.以下是简单的举例 复制代码 代码如下: var iNumber

  • JavaScript中的条件判断语句使用详解

    在写一个程序,可能有一种情况,当你需要采用一个路径出给定两个路径.所以,需要使用条件语句,让程序来做出正确的决策和执行正确的行动. JavaScript支持其用于执行根据不同的条件不同的操作条件语句.在这里,我们将解释if..else语句. JavaScript支持if..else语句的形式如下: if 语句 if...else 语句 if...else if... 语句. if 语句: if语句是基本的控制语句,它允许JavaScript来作出决定,有条件地执行语句. 语法: if (expr

  • 高性能JavaScript循环语句和条件语句

    一.循环语句 众所周知,常用的循环语句有for.while.do-while以及for-in,forEach.除了for-in和forEach性能略低外,平时我们对前三者的选择更多的是基于需求而非性能考虑,今天我们就对它们各自的性能做个测试,告诉我们最极端的情况下还能做哪些优化. 首先我们来谈谈为何for-in和forEach会比其他的慢.for-in一般是用在对象属性名的遍历上的,由于每次迭代操作会同时搜索实例本身的属性以及原型链上的属性,所以效率肯定低下:而forEach是基于函数的迭代(需

  • 如何利用JavaScript编写更好的条件语句详解

    前言 在任何编程语言中,代码需要根据不同的条件在给定的输入中做不同的决定和执行相应的动作. 例如,在一个游戏中,如果玩家生命点为0,游戏结束.在天气应用中,如果在早上被查看,显示一个日出图片,如果是晚上,则显示星星和月亮.在这篇文章中,我们将探索JavaScript中所谓的条件语句如何工作. 如果你使用JavaScript工作,你将写很多包含条件调用的代码.条件调用可能初学很简单,但是还有比写一对对if/else更多的东西.这里有些编写更好更清晰的条件代码的有用提示. 1. 数组方法 Array

  • python里的条件语句和循环语句你了解多少

    目录 前言 一.条件语句 1.什么是条件语句 2.if 语句的基本形式 3.if 语句多个判断条件的形式 4.if 语句多个条件同时判断 5.if 嵌套 二.循环语句 1.什么是循环语句 2. for 循环语句 3. range() 函数 4.While 循环语句 5.for 循环和 whlie 循环的区别 6.嵌套循环 三.条件语句和循环语句综合实例 1.打印九九乘法表 2.判断是否是闰年 总结 前言 通常都听到别人说,计算机很牛逼,很聪明,其实计算机一点都不聪明,光是你要跟他沟通,都会气 s

  • Python条件语句的使用

    目录 if 条件判断语句 条件语句嵌套 你可能不知道的条件操作 python条件判断语句案例 python条件语句使用 if 表达式,难度不高,需要注意的是嵌套用法,以及如何设置对应的条件. if 条件判断语句 python 语句是按固定顺序执行的,先执行前面的语句,再执行后面的语句.如果你像要程序按照你自己定制的流程执行,就需要用到流程控制的语句,最主要用到的是条件语句和循环语句. 条件语句用 if 表示,它表示当满足某个条件时,执行下面的分支代码.当条件不满足时,则跳过下面的分支代码. 在互

  • Python的条件语句与运算符优先级详解

    Python 条件语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非空(null)值为true,0 或者 null为false. Python 编程中 if 语句用于控制程序的执行,基本形式为: if 判断条件: 执行语句-- else: 执行语句-- 其中"判断条件"成立时(非零),则执行后面的语句,而执行内容可以多行,以缩进来区分表示同一范围. el

  • Python 专题二 条件语句和循环语句的基础知识

    前面讲述了"专题一.函数的基础知识",而这篇文章讲述的Python的条件语句和循环语句的基础知识.主要内容包括: 1.条件语句:包括单分支.双分支和多分支语句,if-elif-else 2.循环语句:while的使用及简单网络刷博器爬虫 3.循环语句:for的使用及遍历列表.元组.文件和字符串 前言: 语句块 在讲诉条件语句.循环语句和其他语句之前,先来补充语句块知识.(前面讲函数时已经用到过) 语句块并非一种语句,它是在条件为真(条件语句)时执行或执行多次(循环语句)的一组语句.在代

  • Java使用条件语句和循环结构确定控制流(实例)

    与任何程序设计语言一样,Java使用条件语句和循环结构确定控制流.本文将简单讲解条件.循环和switch. 一.块作用域 块(block),即复合语句.是指由一对大括号括起来的若干条简单的Java语句.块确定了变量的作用域. 比如: public class Code { static { System.out.println("1"); } { System.out.println("2"); } public Code() { System.err.printl

  • 全面掌握Java中的循环控制语句与条件判断语句的使用

    循环控制 可能存在一种情况,当我们需要执行的代码块数次,通常被称为一个循环. Java有非常灵活的三循环机制.可以使用以下三种循环之一: while 循环 do...while 循环 for 循环 截至Java5,对增强的for循环进行了介绍.这主要是用于数组. while 循环 while循环是一个控制结构,可以重复的特定任务次数. 语法 while循环的语法是: while(Boolean_expression) { //Statements } 在执行时,如果布尔表达式的结果为真,则循环中

随机推荐