视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
JavaScript中for、forin、forof、forEach的用法小结(附代码)
2020-11-27 19:28:45 责编:小采
文档
 本篇文章给大家带来的内容是关于JavaScript中 for、for in、for of、forEach的用法小结(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

在JavaScript中,我们经常需要去循环迭代方法操作数组对象等,常见等循环方法有 for、for in、for of、forEach等。

1.for循环

for循环是最基础常见的一种循环,圆括号中需要三个表达式,由分号分隔,最后面是一个花括号的块语句。

for (var i = 0; i <10; i++){
 if (i === 5) {
 continue; //跳出当前循环
 } else if (i === 8) {
 break; //结束循环
 }
 console.log(i);
}

for循环中的语句

continue 语句用来跳出本次循环,但会继续执行后面的循环。
break 语句用来结束循环,后面的循环不会再执行。
return 并不能用来跳出for循环,return语句只能出现在函数体内,它会终止函数的执行,并返回一个指定的值。

使用for循环中遇到的问题

你可能会遇到在for循环使用一个异步操作,这也是一个很常见的面试题。在如下场景,你需要将一批id从0到9的用户名数据请求回来,并将id做为key,name为value塞到一个对象里,代码可能会是这样的

var users = {};
for (var i = 0; i < 10; i++) {
 ajax.get(`/api/userName/${i}`).then(res => {
 users[i] = res.name;
 });
}

最后users对象的数据结果并非我们所想的那样,而是{10: '最后一个请求回来的用户名'}。这是因为异步请求的原因,由于事件队列机制,for循环会先全部执行完成,而异步请求会在后面的不定时间内完成,并且调用then方法被事件队列排在了后面,而此时在任意一个then方法内i变量已经在最后一次循环中被递增到等于10,在不停的调用then方法时,users对象key为10的value会被一直改写直到最后一个请求结束。

使用 let 块级作用域解决

var users = {};
for (let i = 0; i < 10; i++) {
 ajax.get(`/api/userName/${i}`).then(res => {
 users[i] = res.name;
 });
}

将递增变量i使用let声明即可解决,let 语句声明一个块级作用域的本地变量,花括号里是一个块,每次循环都使用该块级作用域中的变量,可以看作每次循环的块都是相互隔离的,变量只会在该作用域内生效。

使用函数闭包作用域解决

var users = {};
for (var i = 0; i < 10; i++) {
 (function () {
 var j = i;
 ajax.get(`/api/user/${j}`).then(res => {
 users[j] = res.name;
 });
 }());
}

我们将异步方法包在一个立即执行函数里面,通过var j声明的变量去承接在该函数内i变量的值,由于立即执行函数形成了一个闭包作用域,变量j在每一个作用域内都是单独存在的。

使用函数参数作用域解决

var users = {};
for (var i = 0; i < 10; i++) {
 (function (value) {
 ajax.get(`/api/user/${value}`).then(res => {
 users[value] = res.name;
 });
 }(i));
}

将变量i作为立即执行函数的参数传递进来,参数也具有各自的作用域,函数参数只在函数内起作用,是局部变量。

2.for in循环(es5)

for...in语句以任意顺序遍历一个对象的可枚举属性,遍历的顺序可能因浏览器实现方式有所不同。所遍历的内容可以是一个对象、数组、字符串、arguments等。使用Object.defineProperty方法可以为对象属性定义是否可以枚举。

枚举

在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。对象的propertyIsEnumerable方法可以判断此对象是否包含某个属性,并且返回这个属性是否可枚举。
Object, Array, Number等内置的方法和属性都是不可枚举的

const obj = {};
Object.defineProperty(obj, 'city', {value: '北京', enumerable: false});
const isEnumerable = obj.propertyIsEnumerable('city');
console.log(obj); // {city: "北京"}
console.log(isEnumerable); //false

for...in可以遍历可枚举但对象,包括不是它本身但存在于原型链上的属性。

const obj = {a:1, b:2, c:3};
Object.defineProperty(obj, 'd', {value: 4, enumerable: false})
obj.__proto__ = {name: 'ricky', age: '25'}

console.log(obj)

console.log('=====for in=======')
for (var prop in obj) {
 console.log(prop, obj[prop]);
}
console.log('=====Object.keys=======')
console.log(Object.keys(obj))
console.log('=====Object.getOwnPropertyNames=======')
console.log(Object.getOwnPropertyNames(obj))
console.log('=====Object.values=======')
console.log(Object.values(obj))
console.log('=====Object.entries=======')
console.log(Object.entries(obj))

输出结果

我们先使用对象字面量的方式定义量一个obj,然后使用Object.defineProperty方法定义key为d的一个不可枚举属性,然后修改原型链__proto__,为其赋值了name, age两个属性。

  1. for in遍历出除属性名为d以外的所有可枚举属性,包括其原型链上的属性

  2. Object.keys方法会返回一个由对象的自身可枚举属性名(key)组成的数组,其原型链上的属性没有被包含

  3. Object.getOwnPropertyNames方法会返回一个由对象的自身所有属性名(key)组成的数组,包括可枚举和不可枚举的属性

  4. Object.values方法会返回一个由对象的自身可枚举属性的值(value)组成的数组

  5. Object.entries方法会返回一个由对象的自身可枚举属性的键值对(key和value)组成的数组

for in会循环所有可枚举的属性,包括对象原型链上的属性,循环会输出循环对象的key,如果循环的是一个数组则会输出下标索引(index)。

in 运算符

in 运算符测试一个对象其自身和原型链中是否存在该属性。

const obj = {name: 'ricky'};
Object.defineProperty(obj, 'city', {value: '北京', enumerable: false})
obj.__proto__ = {age: '25'}

console.log('name' in obj); // true
console.log('city' in obj); // true
console.log('age' in obj); // true
console.log('sex' in obj); // false

for of(es6) 循环可迭代对象

for of循环可迭代对象(包括 Array,Map,Set,String,TypedArray,类数组的对象(比如arguments对象、DOM NodeList 对象)、以及Generator生成器对象等)。

const array = [{a: 1}, {b: 2}, {c: 3}];
array.name = 'ricky';

console.log(array)
console.log('=====for of=======')
for (var prop of array) {
 console.log(prop);
}
console.log('=====for in=======')
for (var prop in array) {
 console.log(prop);
}

for of 与 for in 不同处

  1. 与for in不同的是,for of不能循环普通对象({key: value})

  2. for of不会将循环对象中自定义的属性内容循环出来

  3. for in 是遍历键名(key或index),而for of是遍历键值(value)。

forEach、map 循环

forEach() 方法对数组的每个元素执行一次提供的函数,其中函数有三个参数,依次为:当前循环项的内容、当前循环的索引、循环的数组。

const array = ['a', 'b', 'c'];
array.forEach(function(value, index, data) {
 console.log(value, index, data);
});
// 
输出 // a 0 ["a", "b", "c"] // b 1 ["a", "b", "c"] // c 2 ["a", "b", "c"]

map() 方法会依次循环每一项,并且返回结果映射组成一个新的数组。

const array = [1, 2, 3];
const newArray = array.map(function(value, index, data) {
 return value * 2;
});
console.log(newArray);
//
输出 [2, 4, 6]

使用forEach、map不能中断循环,方法会将每项内容都执行完成才会结束循环。

使用every或 some 提前结束循环

every循环当返回false时循环即会结束, some方法在循环返回true时结束循环,利用这个特性使用every和some方法都可以跳出循环。

const arr = [1, 2, 3, 4, 5];
arr.every(function(value){
 console.log(value);
 if(value === 3) {
 //every 循环当返回false时结束循环
 return false;
 }
 return true //every 循环需要返回true,没有返回值循环也会结束
});

arr.some(function(value){
 console.log(value);
 if(value === 3) {
 //some 循环当返回true时结束循环
 return true;
 }
});

下载本文
显示全文
专题