资讯专栏INFORMATION COLUMN

Javascript 深入学习循环

Cristalven / 2959人阅读

摘要:递归函数还会受到浏览器调用栈的大小的限制。虽然迭代也会导致性能问题,但是使用优化的循环就可以代替长时间运行的递归函数,可以提高新能,因为运行一个循环比反复调用一个函数的开销要小。

本文章记录本人在深入学习js循环中看书理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习。

选择正确的循环体
  

在大部分编程语言中,代码执行的时间多数消耗在循环的执行上。

js定义了4种类型的循环:for, while, do while, for in

for循环是最常用的循环结构,它由四个部分组成:

初始化体

前测条件

后执行条件

循环体。

当遇到一个for循环的时候,初始化体首先执行,然后进入前测条件。如果前测条件的计算为true,就会执行循环体,然后运行后执行条件。

Javascriptfor (var i = 0; i < 10; i++) {
    // 循环体
};

while循环是一个简单的前测循环,由一个前测条件和一个循环体构成。在执行循环体之前,先对前测条件进行计算。如果为true就执行循环体。否则就会跳过循环体。

Javascriptvar i = 1;
while (i < 10) {
    // 循环体
    i ++;
};

do while循环是js中唯一的一种后测试的循环,它包括两个部分:循环体和后侧条件。记住:在一个do while循环中,循环体至少会运行一次,后测条件决定循环体是否再次运行。

Javascriptvar i = 1;
do {
    // 循环体
} while (i++ < 10)

for in循环有一个非常特殊的用途:可以枚举任何对象的命名函数属性。

Javascriptfor (var attr in object) {
    // 循环体
};

每一次循环,属性都会被对象的属性的名字(一个字符串)填充,直到所有的对象属性遍历完才会返回。返回的属性包括对象的使实例属性和对象从原型链基础来的属性。

想要提高循环性能,第一步选用哪种循环。在这四个循环里面,for in循环执行的速度都比其他三个循环要慢。

比较 for 和 while

大部分情况下我们都不会采用for in循环,但是其他的循环类型性能都相当,难以确定哪种循环执行速度更快。选择循环类型应该基于需求而不是性能。

可以通过设计forwhile循环来完成特定动作的重复性操作。从3个目标来分析如何正确的选用forwhile循环。

语义角度比较

forwhile循环可以按照下面的模式来进行互相的转换。

Javascriptfor (initialization; test; increment) // 声明并且初始化循环变量,循环条件,递增循环变量
    statements // 可执行的循环语句

相当于:

Javascriptinitialization  // 声明并且初始化循环变量
while (test) {  // 循环条件
    statements  // 可执行的循环语句
    increment   // 递增循环变量
}

for循环是以循环变量的变化来控制循环进程的,即for循环流程是预先计划好的,虽然中途可能会因存在异常情况或特别情况而退出循环,但是循环的规律是有章可循的。这样的话就方便预知循环的次数和每次循环的状态信息等等。

while循环根据特定条件来决定循环操作,由于条件是动态的,无法预知条件几时是true或者false,因此该循环操作就具有很大的不确定性,每一次循环时都不知道下一次循环状态如何,只能通过条件的变化来确定。

所以for循环通常用于有规律的重复操作中。while循环通常用于特定条件的重复操作,以及依据特定事件控制的循环等操作。

思维模式角度比较

for循环和while循环在思维模式上也存在差异。

for循环中,将循环的三个要素(起始值、终止值和步长)定义为3个基本表达式作为结构语法的一部分固定在for语句里面,使用小括号;进行语法分隔,这样有利于js的进行快速预编译。

在阅读到for循环结构的第一行代码的时候,就能够获取到整个循环结构的控制方式,然后再根据上面的表达式来决定是否执行循环体内的语句。

Javascriptfor (var i = 0; i < 10; i++) {
    alert(i);
};

可以按照下面的逻辑思维进行总结:

执行循环条件:1 < i < 10、步长为i++

执行循环语句:alert(i);

这种把循环操作的环境条件和循环操作语句分离开的设计能够提高程序的执行效率,同时能够避免因为把循环条件与循环语句混合在一起而造成的错误。

for循环的特异性导致在执行复杂的条件时效率会大大的降低。相对而言,while循环就比较适合运http://naotu.baidu.com/viewshare.html?shareId=auuohz8fwm8k的条件,它将复杂的循环控制放在循环体内执行,而while语句自身仅用于测试循环条件,这样就避免了结构的分隔和逻辑的跳跃。

Javascriptvar a = true, b = 1;
while (a) {  // 在循环体内间接计算迭代
    if (9 < b) {
        a = false;
    }
    alert(b);
    b++;
}

从达到目标的角度比较

有一些循环的循环次数在循环之前就可以先预测,如计算1到100的数字和。而有一些循环具有不可预测性们无法事前确定循环的次数,甚至无法预知循环操作的趋向,这些构成了在设计循环结构时候必须考虑的达成目标需要解决的问题,即使是相同的操作,如果达到的目标的角度不同,可能重复了操作的设计也就不同。

使用递归

许多复杂的算法都是通过比较容易实现的递归实现。如阶乘函数。

Javascriptfunction factorial(n) {
    if (0 === n) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
};

递归函数的问题:错误定义或者缺少终结条件会导致函数运行时间过长,使浏览器出现假死现象。递归函数还会受到浏览器调用栈的大小的限制。

在ES6中js拥有了尾递归优化,详情请看迎接ECMAScript 6, 使用尾递归

使用迭代

可以通过递归函数实现的算法都可以通过迭代来实现。迭代算法通常包括几个不同的循环,分别对应算法过程中的不同方面。虽然迭代也会导致性能问题,但是使用优化的循环就可以代替长时间运行的递归函数,可以提高新能,因为运行一个循环比反复调用一个函数的开销要小。

使用迭代来实现合并排序算法:

Javascriptfunction 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];
};
优化循环结构

循环结构是最浪费资源的一种流程。循环结构中的一点小的损耗都会被放大,从而影响程序运行的效率。

优化结构

循环结构常常是与分支结构混合在一起,所以如何嵌套也就非常的讲究。例如,设计一个循环结构,结构内的循环语句只有在特定的条件下才被执行,

Javascriptvar a = true;
for (var i = 0; i < 10; i++) {
    if (a) {} //条件判断
};

在这个循环里面,if语句会被反复的运行,如果这个if语句是一个固定的条件检测表达式,如果if的条件不会受到循环结构的影响,那么用下面这种结构设计会更加复合:

Javascriptif (a) {
    for (var i = 0; i < 10; i++) {
    };
}

但是if条件表达式受循环结构的制约,那就不能使用这种结构嵌套了。

避免不必要的重复操作

在循环里面经常会存在一些不必要的损耗。下面一个例子:

Javascriptfor (var i = 0; i < 10; i++) {
    var a= [1,2,3,4,5,6,7,8,9,10];
    alert(a[i]);
};

在这个循环里面,每循环一次就会在定义一个新的数组,很明显这是一个重复的操作,把数组放到循环体外面会更加的高效:

Javascriptvar a= [1,2,3,4,5,6,7,8,9,10];
for (var i = 0; i < 10; i++) {
    alert(a[i]);
};

妥善定义循环变量

对于for循环来说,它主要利用循环变量来控制整个结构的运行。当循环变量仅用于结构内部的时候,不妨在for语句外面定义循环的变量,这样也可以优化循环结构。

  

最后,如果文章有什么错误和疑问的地方,请指出。与sf各位共勉!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91499.html

相关文章

  • JS程序

    摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...

    melody_lql 评论0 收藏0
  • 前端基础进阶(十二):深入核心,详解事件循环机制

    摘要:前端基础进阶正是围绕这条线索慢慢展开,而事件循环机制,则是这条线索的最关键的知识点。特别是中正式加入了对象之后,对于新标准中事件循环机制的理解就变得更加重要。之后全局上下文进入函数调用栈。 showImg(https://segmentfault.com/img/remote/1460000008811705); JavaScript的学习零散而庞杂,因此很多时候我们学到了一些东西,但...

    whjin 评论0 收藏0
  • JavaScript 异步

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。写一个符合规范并可配合使用的写一个符合规范并可配合使用的理解的工作原理采用回调函数来处理异步编程。 JavaScript怎么使用循环代替(异步)递归 问题描述 在开发过程中,遇到一个需求:在系统初始化时通过http获取一个第三方服务器端的列表,第三方服务器提供了一个接口,可通过...

    tuniutech 评论0 收藏0
  • JavaScript文章

    摘要:我对知乎前端相关问题的十问十答张鑫旭张鑫旭大神对知乎上经典的个前端问题的回答。作者对如何避免常见的错误,难以发现的问题,以及性能问题和不好的实践给出了相应的建议。但并不是本身有问题,被标准定义的是极好的。 这一次,彻底弄懂 JavaScript 执行机制 本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还不懂,可以揍我。 不论你是javascript新手还是老...

    mumumu 评论0 收藏0
  • javascript深入学习笔记-[数组]

    摘要:记笔记很有必要相信我,大多数人的记忆力是不可靠的。解决方式遍历的顺序不确定因为对象不是有序的。出租过程中赶走了某些房客。具体来说就是说存在某个空间没有元素的数组便是稀疏数组怎么处理将会确认这个位置有没有元素存在。同检查元素是否存在 记笔记很有必要——相信我,大多数人的记忆力是不可靠的。 ——《与时间做朋友》李笑来 数组 值的有序集合 弱类型 数组中的元素可以是各种类型的 ...

    cod7ce 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<