资讯专栏INFORMATION COLUMN

JavaScript 循环

gitmilk / 683人阅读

摘要:所以结果的不同就是后者能将循环内容至少执行一次。当此语句省略时,表示不进行条件判断,循环将一直执行,只有在循环中使用来跳出循环。支持对数组和类数组对象进行循环,不支持普通对象的循环。支持对字符串进行循环遍历。

JavaScript中直接提供的循环,主要有以下几种

while 循环

和其他语言一样,JavaScript中的while循环有两种形式:

while (condition) {
    // 循环内容
}

do {
    // 循环内容
} while (condition)

其中两种形式的不同在于,对condition判断的位置不同,前者先判断,再执行循环体;而后者先执行循环体一次,再进行条件判断。所以结果的不同就是后者能将循环内容至少执行一次。

for 循环

for循环的语法:

for (init; condition; step) {
    // 循环体代码块
}

init 语句 中的内容,会在循环代码开始前执行一次,通常用来声明一些变量。

condition 语句 会在每次循环开始时,进行判断。如果第一次就不满足,则不会进入循环。

step 语句 会在每次循环结束时执行,通常是递增或递减condition中的某个变量。

var arr = [0, 10, 20, 30];

for (var j = 0; j < arr.length; j++) {
    console.log(arr[j]);
}

// 如果在循环体中不会改变数组的长度,用一个变量存储数组长度是个更高效的选择
for (var i = 0, l = arr.length; i < l; i++) {
    console.log(arr[i]);
}

var k = 0,
    length = arr.length;
for (; k < length; k++) {
    console.log(arr[k]);
}

for循环中的init语句,通常用来声明初始变量,其可以有多个,用,分隔即可。而且由于此语句是在循环开始前执行,且只用执行一次,所以如果在外部已经声明过要用的变量了,for循环中的这个语句可以直接省略,如上例中的第三个for循环所示。

for循环的条件语句是在每次循环体开始前进行判断,如果为true,则执行循环体内容,否则结束循环。当此语句省略时,表示不进行条件判断,循环将一直执行,只有在循环中使用break来跳出循环。

for循环的step语句,最常见的就是使用++或者-- 运算符的表达式,不过也可以使用其他任意值的,而且也可以省略,换到循环体中进行改变赋值。

for-in 循环

for-in循环是JavaScript中专门提供用来遍历对象属性的。

var zs = {
    name: "zhang san",
    gender: "male",
    age: 26
};

for (var key in zs) {
    console.log("%s : %s", key, zs[key]);
}
// name : zhang san
// gender : male
// age : 26

不过需要注意一点问题,请看如下示例:

function Person(name, gender) {
    this.name = name;
    this.gender = gender;
}
Person.prototype.sayHello = function() {
    console.log("Hello,I am", this.name, ". I"m a", this.gender);
};

var zs = new Person("zhang san", "male");

for (var key in zs) {
    console.log("%s : %s",key, zs[key]);
}
// name : zhang san
// gender : male
// sayHello : function () {
//    console.log("Hello,I am", this.name, ". I"m a", this.gender);
// }

这次循环遍历中,它还输出了zs原型链上的属性sayHello。这反应出一个问题,for - in 循环会遍历整个原型链,虽然可以使用hasOwnProperty方法进行过滤仅获取自身属性,但其访问的仍是整个原型链,遍历范围较广,所以其效率比较低,通常来说,其效率仅为普通for循环的1/7。

JavaScript中,由于数组也是对象,所以此方法也可以用来遍历数组。

var arr = [1, 2, 3, 4];
for (var i in arr) {
    console.log(typeof i);
    if (arr.hasOwnProperty(i))
        console.log("arr[%s] : %d", i, arr[i]);
    else
        console.log("arr.%s : ", i, arr.[i]);
}
// string
// arr[0] : 1
// string
// arr[1] : 2
// string
// arr[2] : 3
// string
// arr[3] : 4
// string
// arr.where : function ...
// string
// arr.groupBy : function ...
// string
// arr.has : function ...

这个输出的结果或许不是你想象的样子,然而他就是这样。我们认为的索引,实际是对象的键名,所以其是String类型。对于数组来说,和对象一样,在其原型上扩展的方法wheregroupByhas也都被输出了。 或许会有疑问,数组不是有length属性吗,为什么没有输出呢?原因在于数组的length属性是不可枚举属性,for - in循环不会访问这些属性。关于此的更多知识可参考MDN - 属性的可枚举性和所有权

Array Javascript 中是一个对象, Array 的索引是属性名。事实上, Javascript 中的 “array” 有些误导性, Javascript 中的 Array 并不像大部分其他语言的数组。首先, Javascript 中的 Array 在内存上并不连续,其次, Array 的索引并不是指偏移量。实际上, Array 的索引也不是 Number 类型,而是 String 类型的。我们可以正确使用如 arr[0] 的写法的原因是语言可以自动将 Number 类型的 0 转换成 String 类型的 "0" 。所以,在 Javascript 中从来就没有 Array 的索引,而只有类似 "0" 、 "1" 等等的属性。

for - in 循环原本就是用来遍历对象的,用其来遍历数组并不合适,不过也有例外的情况,比如稀疏数组:

var arr = new Array(1000);

arr[0] = 1;
arr[99] = 3;
arr[999] = 5;
// for循环
for (var i = 0, l = arr.length; i < l; i++) {
    console.log("arr[%s]", i, arr[i]);
}
console.log("i :" , i);
// ...
// arr[0] 1
// ...
// arr[99] 3
// ...
// arr[999] 5
// i : 1000


// for - in 循环
var count = 0;
for(var j in arr){
    count ++ ;
    if(arr.hasOwnProperty(j)){
        console.log("arr[%s]", j, arr[j]);
    }
}
console.log("count : ", count);
// arr[0] 1
// arr[99] 3
// arr[999] 5
// i : 1000

直接使用普通的for循环,循环次数为数组长度1000次,而使用for - in循环,仅仅循环了3次。

上面看起来循环的效率是高了不少,但是在前面已经说过了,for - in 的专职是对象的遍历(类似的还有Object.keys()),因此上面的方案并非是一个完美的方案,更好的做法是用是数组本身的遍历方法forEach(forEachES5中新增,需要IE9+)。

var arr = new Array(1000);
arr[0] = 1;
arr[99] = 3;
arr[999] = 5;

var count = 0;
arr.forEach(function(value, index) {
    count++;
    console.log(typeof index);
    console.log(index, value);
});
console.log("count", count);
// number
// 0 1
// number
// 99 3 
// number
// 999 5
// count 3

这样就高效地进行了循环遍历,而且数组的索引index也被正确地识别为了number类型。

或许你会想到jQuery中提供的工具方法$.each()$.map()或者实例jQuery对象的eachmap方法,但是结果会让你失望的,依旧会是循环1000次,以下是示例:

var count1 = 0;
$.each(arr, function(index, value) {
    count1++;
    console.log(index, value);
});
console.log("count1",count1);
// count1 1000

var count2 = 0;
$.map(arr,function(value,index){
    count2++;
    console.log(index, value);
});
console.log("count2",count2);
// count2 1000

从上面对比来看Array.prototype.forEach方法似乎不错,但其循环效率仍然不如普通的for循环,不过优势在于在稀疏数组的处理。

不过forEach方法,严格来算并不算是循环,原因在于,它并不能响应循环应有的breakcontinue语句。准确地讲,它是一个遍历函数,对每个元素执行指定的回调函数。

for-of循环

ES6中又新增了for - of 循环,它与for - in循环类似,但又有所不同。

for - of 支持对数组类数组对象进行循环,不支持普通对象的循环。

for - of 支持对字符串进行循环遍历。

for - of 支持对MapSet (ES6 中新增的类型)对象遍历。

for - of 不支持普通对象的循环遍历。

// 数组
var arr = [0, 1, 2, 3, 4, 5];

for (let index of arr) {
    if (index === 1) continue;
    if (index === 4) break;
    console.log(typeof index);
    console.log(index, arr[index]);
}
// number
// 0 0
// number
// 2 2
// number
// 3 3

当索引为1时直接进行下一次循环,而当索引为4时,直接退出循环,因此输出如上结果,也同样正确识别索引为number类型。

// 类数组
// 类数组
var divs = document.querySelectorAll("div");

for (let i of divs) {
    console.log(i.classList);
}
// ["container", "md-doc", value: "container md-doc"]
// ["doc-cata", value: "doc-cata"]
// ["nicescroll-rails", "nicescroll-rails-vr", value: "nicescroll-rails nicescroll-rails-vr"]
// ["nicescroll-cursors", value: "nicescroll-cursors"]
// ["nicescroll-rails", "nicescroll-rails-hr", value: "nicescroll-rails nicescroll-rails-hr"]
// ["nicescroll-cursors", value: "nicescroll-cursors"]

for (let k in divs) {
    console.log(k, divs[k].classList);
}
// "0" ["container", "md-doc", value: "container md-doc"]
// "1" ["doc-cata", value: "doc-cata"]
// "2" ["nicescroll-rails", "nicescroll-rails-vr", value: "nicescroll-rails nicescroll-rails-vr"]
// "3" ["nicescroll-cursors", value: "nicescroll-cursors"]
// "4" ["nicescroll-rails", "nicescroll-rails-hr", value: "nicescroll-rails nicescroll-rails-hr"]
// "5" ["nicescroll-cursors", value: "nicescroll-cursors"]
// length undefined
// item undefined
// keys undefined
// values undefined
// entries undefined
// forEach undefined

for - of循环用于类数组对象的处理时,需要注意,of关键字前面的变量即为类数组对象中的键值,如上例所示,在for - of循环中i即代表着DOM nodelist 中的每个对象,而在for - in 循环中k代表的仅仅是对象的键名。

参考链接

深入了解 JavaScript 中的 for 循环

JavaScript while循环

JavaScript for循环

MDN - 属性的可枚举性和所有权

原文发表在我的博客JavaScript 循环,欢迎访问!

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

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

相关文章

  • JavaScript运行机制和事件循环

    摘要:主线程不断重复上面的三步,此过程也就是常说的事件循环。所以主线程代码执行时间过长,会阻塞事件循环的执行。参考资料这一次,彻底弄懂执行机制任务队列的顺序机制事件循环搞懂异步事件轮询与中的事件循环 1. 说明 读过本文章后,您能知道: JavaScript代码在浏览器中的执行机制和事件循环 面试中经常遇到的代码输出顺序问题 首先通过一段代码来验证你是否了解代码输出顺序,如果你不知道输出...

    Ververica 评论0 收藏0
  • 回到基础:用循环优化 JavaScript 程序

    摘要:有两个主要因素有助于改善循环性能每次迭代完成的工作和迭代次数。第一个是标准的循环,它与其他类语言的语法相同循环体这可能是最常用的循环结构。解析循环由四部分组成初始化,预测试条件,循环体和后执行。它将会不断执行,直到返回所有属性为止。 翻译:疯狂的技术宅https://medium.freecodecamp.o... 本文首发微信公众号:前端先锋欢迎关注,每天都给你推送新鲜的前端技术...

    harriszh 评论0 收藏0
  • 什么是JavaScript 事件循环 ?

    摘要:此事件队列的美妙之处在于它只是函数等待被调用和移动到调用栈的一个临时存放区域。在事件循环不断监视调用栈是否为空现在确实是空的时候调用创建一个新的调用栈来执行代码。在执行完之后进入了一个新的状态这个状态调用栈为空事件记录表为空事件队列也为空。 这篇文章是对个人认为讲解 JavaScript 事件循环比较清楚的一篇英文文章的简单翻译,原文地址是http://altitudelabs.com...

    tracymac7 评论0 收藏0
  • javascript遍历方法总结

    摘要:总之,是用来循环带有字符串的对象的方法。循环里引入了一种新的循环方法,它就是循环,它既比传统的循环简洁,同时弥补了和循环的短板。 forEach 循环 JavaScript诞生已经有20多年了,我们一直使用的用来循环一个数组的方法是这样的: for (var index = 0; index < myArray.length; index++) { console.log(myAr...

    BothEyes1993 评论0 收藏0
  • JavaScript单线程事件循环(Event Loop)那些事

    摘要:概述本篇主要介绍的运行机制单线程事件循环结论先在中利用运行至完成和非阻塞完成单线程下异步任务的处理就是先处理主模块主线程上的同步任务再处理异步任务异步任务使用事件循环机制完成调度涉及的内容有单线程事件循环同步执行异步执行定时器的事件循环开始 1.概述 本篇主要介绍JavaScript的运行机制:单线程事件循环(Event Loop). 结论先: 在JavaScript中, 利用运行至...

    Shisui 评论0 收藏0

发表评论

0条评论

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