4.1 循环

4.1.1 循环的类型

主要有四种循环类型:for、while、do-while和for-in。

--------------------------------------------------------------------
注:如果你对python感兴趣,我这有个学习Python基地,里面有很多学习资料,感兴趣的+Q群:895817687
--------------------------------------------------------------------// 1、for循环:初始化、前测条件、后执行体和循环体组成。for (var i=0; i < 10; i++){// 循环体}// 2、while循环:前测条件和循环体组成。var i = 0;while(i < 10){// 循环体i++;}// 3、do-while循环:循环体和后测条件组成。var i = 0;do {// 循环体} while (i++ < 10);// 4、for-in循环:可以枚举任何对象的属性名。for (var prop in object){// 循环体}

注意:for循环初始化的var语句会创建一个函数级别的变量,而不是循环级。由于JavaScript只有函数级作用域,因此for循环中定义一个新变量相当于在循环体外定义一个新变量。

4.1.2 循环性能

循环的性能提升主要由这几个方面入手:
1、循环的类型:除了for-in循环比其他三种循环明显要慢外,其他几种性能都差不多。所以除非明确需要迭代一个属性数量未知的对象,否则避免使用for-in循环;
2、减少迭代的工作量:将需要多次查找的属性存入局部变量中重复使用,并使用倒序循环;

    // 原始版本for (var i=0; i < items.length; i++){process(items[i]);}var j=0;while (j < items.length){process(items[j++]]);}var k=0;do {process(items[k++]);} while (k < items.length);
    // 最小化属性查找:在大多数浏览器中能节省25%运行时间for (var i=0, len=items.length; i < len; i++){process(items[i]);}var j=0,count = items.length;while (j < count){process(items[j++]]);}var k=0,num = items.length;do {process(items[k++]);} while (k < num);
    //最小化属性查找并反转:比原始版本快50%~60%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--);

3、减少迭代次数:使用“达夫设备(Duff’s Device)”模式限制迭代次数。Duff’s Device背后的基本理念:每次循环最多可调用8次process(),循环迭代的次数为总数除以8。

    // 原始版Duff’s Devicevar iterations = Math.floor(items.length / 8),startAt = items.length % 8,i = 0;do {switch(startAt){case 0: process(items[i++]);case 7: process(items[i++]);case 6: process(items[i++]);case 5: process(items[i++]);case 4: process(items[i++]);case 3: process(items[i++]);case 2: process(items[i++]);case 1: process(items[i++]);}startAt = 0;} while (--iterations);
    // 升级版Duff’s Device:尽管这种方式用两次循环代替之前一次循环,但移除了循环体中的switch语句,速度比原始更快。var i = items.length % 8;while(i){process(items[i--]);}i = Math.floor(items.length / 8);while(i){process(items[i--]);process(items[i--]);process(items[i--]);process(items[i--]);process(items[i--]);process(items[i--]);process(items[i--]);process(items[i--]);}

性能优化:迭代次数<1000,和常规循环结构比性能提升微不足道;迭代次数>1000,Duff’s
Device模式性能会有明显提升。在5000次迭代中,性能比常规提升70%。

4.1.3 基于函数的迭代

ECMA-262标准第四版介绍了本地数组对象的一个新方法forEach()。此方法遍历一个数组的所有成员,并在每个成员上执行一个函数。在每个元素上执行的函数作为 forEach()的参数传进去,并在调用时接收三个参数,它们是:数组项的值,数组项的索引,和数组自身。

    items.forEach(function(value, index, array){process(value);});

性能优化:在所有情况下,基于循环的迭代比基于函数的迭代快8倍。因此在运行速度严格要求时,基于函数的迭代不是合适的选择。

4.2 条件语句

4.2.1 if-else对比switch

多数情况下,switch比if-else运行的要快,但只有条件数量很大时才快的比较明显。这两句的主要性能区别是:当条件增加时,if-else性能负担增加的程度比switch要多。

性能优化:if-else适用于判断两个离散值或几个不同的值域;当判断多个离散值时,switch语句是更佳选择。

4.2.2 优化if-else

优化目标:最小化到达正确分支前所需判断的条件数量。
优化原则:

将最可能出现的条件放在首位,最小概率出现的的条件放在末尾;
使用if-else嵌套:
嵌套过程中使用二分法把值域分成一系列区间,逐步缩小范围。
从而减少条件判断次数。

  • 反例
    // 最多要判断10次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;}
  • 正例
    // 最多判断4次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.2.3 查找表

  • 描述

JavaScript中可以使用数组和普通对象来构建查找表,特别是在条件语句数量很大的时候,性能比条件语句快很多。

  • 原因

当你使用查找表时,必须完全抛弃条件语句。这个过程变成数组项查询或者对象成员查询。主要优点:不用书写任何条件语句,即便候选值数量增加时,也几乎不会产生额外的开销。

  • 反例
    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;}
  • 正例
    // 将返回值存入数组var results = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10]// 利用数组返回当前结果return results[value];

4.3 递归

4.3.1 调用栈限制

JavaScript引擎支持的递归数量与JavaScript调用栈大小直接相关。如果超出了浏览器的调用栈限制,就会抛出调用栈溢出的异常。

4.3.2 递归模式

递归一般有两种模式:直接递归模式和隐伏模式。第二种模式在出现问题时,很难定位。

    // 1、直接调用模式function recurse(){recurse();}recurse();// 2、隐伏模式function first(){second();}function second(){first();}first();

4.3.3 迭代

  • 描述

任何递归能实现的算法,迭代也能实现。

  • 原因

使用优化后的循环替代长时间运行的递归函数可以提升性能,因为运行一个循环比反复调用一个函数的开销要少很多。

  • 反例
    function merge(left, right){var result = [];while (left.length > 0 && right.length > 0){if (left[0] < right[0]){result.push(left.shift());} else {result.push(right.shift());}}return result.concat(left).concat(right);}function mergeSort(items){if (items.length == 1) {return items;}var middle = Math.floor(items.length / 2),left = items.slice(0, middle),right = items.slice(middle);return merge(mergeSort(left), mergeSort(right));}
  • 正例
    function merge(left, right){var result = [];while (left.length > 0 && right.length > 0){if (left[0] < right[0]){result.push(left.shift());} else {result.push(right.shift());}}return result.concat(left).concat(right);}// 使用迭代后比递归要慢一些,但不会受到调用栈限制。是避免栈溢出错误的方法之一。function mergeSort(items){if (items.length == 1) {return items;}var work = [];for (var i=0, len=items.length; i < len; i++){work.push([items[i]]);}work.push([]); // 如果数组长度为奇数for (var lim=len; lim > 1; lim = (lim+1)/2){for (var j=0,k=0; k < lim; j++, k+=2){work[j] = merge(work[k], work[k+1]);}work[j] = []; // 如果数组长度为奇数}return work[0];}

4.3.4 Memoization

Memoization是一种避免重复工作的方法,它缓存前一个计算结果后供后续计算使用。
以阶乘函数为例:

    function factorial(n){if (n == 0){return 1;} else {return n * factorial(n-1);}}// 使用过程中factorial()函数被调用了18次,而所有必要的计算在第一行代码里已经处理掉了。
var fact6 = factorial(6);
var fact5 = factorial(5);
var fact4 = factorial(4);

使用Memoization后,将第一次计算的结果缓存起来,后期再调用的时候,直接从缓存中读取结果。

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

《高性能JavaScript》第四章 算法和流程控制相关推荐

  1. Java基础教程【第四章:Java流程控制】

    章节目录 1. 顺序结构 2. 分支语句 2.1 if 语句 2.2 if-else 语句 2.3 if-else if - -else语句 2.4 Switch 语句 3. 循环语句 3.1 whi ...

  2. Javascript第四章匿名函数第七课

    匿名函数的作用: 1.用于回调 2.一次性执行函数 Javascript第四章定义函数的形式.回调函数第五课 https://blog.csdn.net/qq_30225725/article/det ...

  3. 【PAT】第四章 算法初步

    第四章 算法初步 目录 第四章 算法初步 4.1 排序 4.1.1 选择排序 4.1.2 插入排序 4.1.3 排序题与sort函数的应用 strcmp 计算排名 4.2 散列 4.2.1 散列 1. ...

  4. 《STM32单片机开发应用教程(HAL库版)—基于国信长天嵌入式竞赛实训平台(CT117E-M4)》第四章4.3 按键控制实验

    写在前面-- <STM32单片机开发应用教程(HAL库版)-基于国信长天嵌入式竞赛实训平台(CT117E-M4)>第四章4.3 按键控制实验,讲述按键控制的编程方法 官方例程下载:http ...

  5. 可视化导论 - 第四章 数据可视化流程 - 学习笔记

    第4章 数据可视化流程 4.1 数据可视化流程 以数据流向为主线,其主要模块包括数据采集.数据处理和变换.可视化映射和用户感知. 4.2 数据处理和数据变换 4.2.1 数据滤波 数据滤波器在信号处理 ...

  6. JavaScript基础-基本数据类型和基本流程控制

    2019独角兽企业重金招聘Python工程师标准>>> JavaScript基础1 一.基本数据类型 1.Number 2.String 3.Null 4.Undefined 5.t ...

  7. 前端JavaScript(1) --Javascript简介,第一个JavaScript代码,数据类型,运算符,数据类型转换,流程控制,百度换肤,显示隐藏...

    一.Javascript简介 Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) Jav ...

  8. python 全栈开发,Day50(Javascript简介,第一个JavaScript代码,数据类型,运算符,数据类型转换,流程控制,百度换肤,显示隐藏)...

    一.Javascript简介 Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) Jav ...

  9. JavaScript基本语法,函数,流程控制

    1.JS概述 1.1概述 JavaScript 1995年~~ 是基于对象和事件驱动的脚本语言,应用在客户端 基于对象:提供了很多对象,可以直接使用 事件驱动:js实现动态效果 作用:提高用户体验,提 ...

最新文章

  1. Windows 文件服务器升级跨林迁移(二)
  2. JSON简介以及用法汇总
  3. session 对象的简单实例
  4. Java 设计模式之观察者模式
  5. 关键词词云怎么做_制作CVPR 热词云(并爬取pdf地址 名称)
  6. Struts2 datetimepicker 日期月份乱码解决
  7. 实例21:python
  8. linux命令行模式下实现代理上网 专题
  9. java实现rabbitmq任务模型(work queues), 生产者 消费者 消息队列 能者多劳
  10. Java常用设计模式的实例学习系列-绪论
  11. 手机12306买卧铺下铺技巧_手机12306怎么买下铺(微信买火车票指定下铺)
  12. 【Unity3D】【UI】Cannot restructure Prefab instance.
  13. 主板电源开关接口图解_图解:主板电线接法(电源开关、重启等)
  14. 南京:全面启用商品房买卖电子合同
  15. 为防泄密 新加坡政府将断掉公务员的网络连接
  16. 淘宝抢券python代码,能够对实时抢券和清空购物车。
  17. 建筑企业并购:人才整合的三大误区
  18. mysql administrator教程_MYSQL administrator 使用
  19. python open函数参数newline_TypeError:“newline”是此函数的无效关键字参数
  20. 肾有多好,人就有多年轻。男女通用

热门文章

  1. 性能优化之数据库和数据源连接池配置
  2. Java向数据库中插入Boolean类型的字段
  3. java顺序结构类型,Java类的完整构造执行顺序
  4. ajax请求返回json实例,Jquery Ajax 学习实例2 向页面发出请求 返回JSon格式数据
  5. jquery+原生js模拟淘宝输入框下拉提示
  6. 问题之JVM_Bind
  7. 2017年 第08届 蓝桥杯 Java B组 决赛真题详解及小结
  8. Android复习10【Service与Thread的区别、Service的生命周期、Service生命周期解析(相关方法详解、启动方式的不同、绑定)、音乐播放器+服务】
  9. Kotlin实战指南六:可空类型、非可空类型
  10. CentOS 初体验四: 阿里云服务器开启8080端口