Array,数组,是javaScript数据类型里面的引用类型的数据,在我们前端开发的过程中,可以说是使用的非常非常的频繁,而对数组的循环也是我们最常见的操作,今天给大家分享一下我自己在前端开发过程中对数组循环操作使用的一些个人经验和小技巧:
常用数组循环方法
for
for in
for of
forEach()
map()
some()
every()
filter()
for循环 `
var arr = [{id: 1, color: 'red'}, {id: 2, color: 'orange'}, {id: 3, color: 'yellow'},
{id: 4, color: 'green'}, {id: 5, color: 'blue'} ];
for (var i = 0, len = arr.length; i < len; i++) {
console.log(arr[i].color)
}
// 输出: 'red', 'orange', 'yellow', 'green', 'blue'
复制代码
` 上面这个for循环应该是各位程序员使用的最最多的一个循环方式是吧,for循环是以声明一个变量i,初始值为0,只要i小于arr.length,i就加加一次,直到不小于为止,则跳出循环。大家在看这段代码的时候,是否有留意到,我把arr.length存储到一个len的变量中,注意哦,这个是for循环使用的小技巧哦,因为在我们循环遍历数组的时候,如果没有事先存储,变量i在每次循环递增之前便会反复去计算数组的长度值,因为只要涉及到计算,肯定就会消耗我们的浏览器对js代码解析的性能,而当我们存储起来,就优化了这个部分,这样做对于我们前端开发来说是非常有必要的呢,下面对for 循环做个总结:
- 一. 使用for循环时请把循环的对象的length存储起来;
- 二. for循环可以使用break中断循环;
- 三. for循环不可以使用return跳出循环;
for in循环 `
var arr = [{id: 1, color: 'red'}, {id: 2, color: 'orange'}, {id: 3, color: 'yellow'},
{id: 4, color: 'green'}, {id: 5, color: 'blue'} ];
for (var item in arr) {
console.log(arr[item].color)
}
// 输出: 'red', 'orange', 'yellow', 'green', 'blue'
复制代码
` 这样看,似乎觉得没有什么毛病,那么在请看下面的代码,仍然是上面这个数组
`
Array.prototype.test = '测试数组';
for (var item in arr) {
console.log(arr[item].color)
}
// 输出: 'red', 'orange', 'yellow', 'green', 'blue', '测试数组'
复制代码
` 大家是不是很惊奇的发现,居然把我们刚定义在原型链的test给输出来了,这样明显不是我们想要的,通过这一点其实就已经说明,for in不适合对数组循环操作,因为for in会把数组原型上的可枚举属性给遍历出来,当然你可以通过hasOwnProperty()方法来判断
`
for (var item in arr) {
if (arr.hasOwnProperty(item)) {
console.log(arr[item].color)
}
}
// 输出: 'red', 'orange', 'yellow', 'green', 'blue'`
复制代码
虽然你这样做可以,但是请明白一点,hasOwnProperty()方法是用来检测当前项是不是实例本身的私有属性的,for in循环始终都会去遍历数组原型上的可枚举对象,这样对于js的性能优化来说是非常不利的。不仅如此,for in的变量item,是字符数据类型,不能直接进行一些数学计算,即使你要操作,你也又会多写一些代码来处理,这样就大大的增加了浏览器对js代码解析的成本了。所以for in更多是使用在object对象的循环上,for in总结下面几点:
- 一.for in循环不适用对数组的循环,因为for in会去遍历原型上的所有可枚举对象,对性能造成极大负担;
- 二.for in循环可以使用break中断循环,不可以使用return返回语句;
- 三.for in循环的变量item是是循环的key值,字符串数据类型;
- 四.for in 适合循环object对象数据。
for of循环
for of是es6提出的一个新的循环方法,也是本次讲解数组循环里唯一介绍的一个es6的方法。for of 语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for of 循环,以替代 for in 和 forEach() ,并支持新的迭代协议。for of 允许你遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等。
`
Array.prototype.test = '测试数组';
var arr = [{id: 1, color: 'red'}, {id: 2, color: 'orange'}, {id: 3, color: 'yellow'},
{id: 4, color: 'green'}, {id: 5, color: 'blue'} ];
for (var item of arr) {
console.log(item.color)
}
// 输出: 'red', 'orange', 'yellow', 'green', 'blue'
var str = 'ABCDEFG';
for (var cur of str) {
console.log(cur)
}
// 输出:A, B, C, D, E, F, G
复制代码
` 看到这里,我们先抛开for of本身的工作机制,我们先来瞅瞅它for in比有哪些不同与优势:
- 一. for of可以在循环的过程中使用break中断循环,但是你会说,for in也可以使用breack中断循环呀;
- 二. for of不会去遍历实例原型上的私有属性,这点很重要哦;
- 三. for of循环里的变量item就是数组元素当前项本身;
- 四. for of不适合遍历object对象,如果非要使用,你需要结合Object.keys()来使用,不然肯定会报错*** is not iterable(不是可迭代的)。
- 五. for of也不可以使用return返回语句,如果不幸你使用了,肯定会看到Illegal return statement(非法返回语句);
OK,我们接下来简单聊聊什么是iterable,可迭代的数据对象,for of循环首先调用集合的Symbol.iterator方法,紧接着返回一个新的迭代器对象。迭代器对象可以是任意具有.next()方法的对象;for of循环将重复调用这个方法,每次循环时调用一次。请看下面例子:
`
var iterable = {
[Symbol.iterator]() {
return {
i: 0,
next() {
if (this.i < 3) {
return { value: this.i++, done: false };
}
return { value: undefined, done: true };
}
};
}
};
for (var value of iterable) {
console.log(value);
} //输出 0, 1, 2
复制代码
` 总结,for in更多适用object循环使用,for of更适用数组和类数组的使用。更多的for of循环的认识,可以到MDN 去查看和学习。
forEach()循环
forEach()是javaScript数组里的内置一个循环方法,在jQuery里有一个类似的方法each(),本章节不会讲jQuery里的each()。forEach()接受一个回调函数,回调函数接受三个参数forEach(function(item, index, ary){}), item是数组元素当前项,index是当前项的索引值,ary是循环数组的本身,下面看代码示例: `
var arr = [{id: 1, color: 'red'}, {id: 2, color: 'orange'}, {id: 3, color: 'yellow'},
{id: 4, color: 'green'}, {id: 5, color: 'blue'} ];
arr.forEach((item, index, ary) => {
console.log(item.color);
console.log(index);
console.log(ary);
})
// 输出: 'red', 'orange', 'yellow', 'green', 'blue';
// 输出: 0, 1, 2, 3, 4
// 输出: 5次:Array(5)
复制代码
` forEach()循环的使用需要了解的特点就是:
- 一.回调函数里的三个参数,各自是谁;
- 二.另外还有一点非常重要,也不可以break中断循环哦。如果你使用了break,肯定会提示报错:Illegal break statement(非法中断语句)。
- 三.forEach()不可以return跳出循环,而你要是使用了return,则更坑,浏览器即不会提示报错,它还会把循环执行完,你要是不了解这个特点,你会蒙蔽的不知道咋回事。
map()循环
map()也是javaScript数组里的内置方法,map()同forEach()一样,接受一个回调函数,回调函数接受三个参数数map(function(item, index, ary){}), item是数组元素当前项,index是当前项的索引值,ary是循环数组的本身,下面看代码示例: `
var arr = [{id: 1, color: 'red'}, {id: 2, color: 'orange'}, {id: 3, color: 'yellow'},
{id: 4, color: 'green'}, {id: 5, color: 'blue'} ];
arr.map((item, index, ary) => {
console.log(item.color);
console.log(index);
console.log(ary);
})
// 输出: 'red', 'orange', 'yellow', 'green', 'blue';
// 输出: 0, 1, 2, 3, 4
// 输出: 5次:Array(5)
复制代码
` 这里的输出和forEach一模一样,没有任何差别,那么问题来了,ECMAScript组织傻吗,干嘛发布两个一模一样的方法呢,no,他们不傻,因为forEach()和map()肯定有差别,看例子:
`
var ary = arr.map((item, index) => {
return item.page
})
console.log(ary)
// 输出新数组: ['red', 'orange', 'yellow', 'green', 'blue']
复制代码
`
这个例子里返回的这个新数组是不会影响原数组的,而且这个返回的机制,对于结合indexOf(),includes()数组查询的操作非常有用。当然map也是不可以在循环体里使用break;因此map可以总结两点对它的认识:
- 一.可以使用return,return出来的是一个新数组,新数组不影响原数组;
- 二.不可以使用break。
some()循环
some()也是javaScript数组里的内置方法,和前面的forEach,map一样接收一个回调函数,回调函数里默认三个参数,参数顺序同样是 item, index, arr(原数组);下面看例子: `
var arr = [{id: 1, color: 'red'}, {id: 2, color: 'orange'}, {id: 3, color: 'yellow'},
{id: 4, color: 'green'}, {id: 5, color: 'blue'} ];
arr.some(function(){
console.log(arguments)
}) // 会输出6次 Arguments(3)
arr.some(function(item, index){
if (index == 4) {
break;
}
console.log(item.color)
}
) // 不会输出,会报错Illegal break statement(非法中断语句)
var bool1 = arr.some(function(item, index){
console.log(item.color) //输出 'red', 'orange', 'yellow', 'green', 'blue'
})
console.log(bool1) //输出 fasle
var bool2 = arr.some(function(item, index){
if (index == 4) {
return true
}
console.log(item.color) //输出 'red', 'orange', 'yellow', 'green'
})
console.log(bool2) //输出 true
var bool3 = arr.some(function(item, index){
if (index == 4) {
return false
}
console.log(item.color) //输出 'red', 'orange', 'yellow', 'green'
})
console.log(bool3) //输出 false
var bool4 = arr.some(function(item, index){
if (index == 4) {
return '' //这里返回值只会返回布尔值,如果你给的返回值不是布尔值,则会给你转换成布尔值
}
console.log(item.color) //输出 'red', 'orange', 'yellow', 'green'
})
console.log(bool4) //输出 false
复制代码
` 通过上面的代码演示,对some方法做如下总结:
- 一.some方法接收一个回调函数,回调函数接收三个参数,item, index, arr(原数组)
- 二.some方法不可以使用break语句中断循环;
- 三.some方法可以使用return语句跳出循环,some接收一个返回值,返回值是布尔值,默认false,return返回时可以主动返回一个true或者false时的布尔,如果返回其他数据类型会转换成布尔值。
every()循环
every()也是javaScript数组里的内置方法,是和上面的some方法非常类似的一个方法,就像是forEach与map的关系一样,every与some非常相似,但是它们还是有差别,下面看代码: `
var arr = [{id: 1, color: 'red'}, {id: 2, color: 'orange'}, {id: 3, color: 'yellow'},
{id: 4, color: 'green'}, {id: 5, color: 'blue'} ];
arr.every(function(){
console.log(arguments)
}) // 会输出1次 Arguments(3)
arr.every(function(item, index){
if (index == 4) {
break;
}
console.log(item.color)
}
) // 不会输出,会报错Illegal break statement(非法中断语句)
var bool1 = arr.every(function(item, index){
console.log(item.color) //输出 'red'
})
console.log(bool1) //输出 fasle
var bool2 = arr.every(function(item, index){
if (index == 4) {
return true
}
console.log(item.color) //输出 'red'
})
console.log(bool2) //输出 false
复制代码
` 到这里,就已经可以总结出every来了,说实话,我自己个人是十分不理解这个方法存在的意义,看下面几点总结:
- 一.every方法接收一个回调函数,回调函数接收三个参数,item, index, arr(原数组)
- 二.every方法不可以使用break语句中断循环;
- 三.every方法不能循环完整个数组,它只能遍历到数组的第一个当前项,every同样接收一个布尔的返回值,这个值就是固定的false。
filter()循环
filter()也是javaScript数组里的内置方法,filter方法,语义上是过滤器,数组的过滤器,通过循环遍历,然后根据条件来返回自己需要的数组当前项,filter是个使用非常频繁的数组方法之一,下面我们看代码例子: `
var arr = [{id: 1, color: 'red'}, {id: 2, color: 'orange'}, {id: 3, color: 'yellow'},
{id: 4, color: 'green'}, {id: 5, color: 'blue'} ];
var ary = arr.filter(function(item, index){
console.log(arguments) // arguments包含三个默认参数,item,index,以及原数组
console.log(item.color); //输出'red', 'orange', 'yellow', 'green', 'blue'
if (index > 1 && index < 4) {
return item
}
})
console.log(ary) //输出[ {id: 2, color: 'orange'}, {id: 3, color: 'yellow'},
{id: 4, color: 'green'}]
复制代码
` 通过代码演示,我们发现filter和前面的所有数组方法一样,接收一个回调函数,回调函数默认三个参数,filter可以接收返回值,返回值默认以一个新数组接收,filter使用return不会跳出循环,下面我们对filter做个总结:
- 一. filter接收一个回调函数,回调函数默认三个参数,item, index, arr(原数组)
- 二. filter接收一个返回值,返回值是个新数组,新数组不影响原数组,
- 三. filter里的return是返回满足自己条件的当前项的,不可以跳出训话,
- 四. filter里不可以使用break中断语句;
最后总结
在本次分享里面,还有好几个可以循环数组的方式没有介绍到,有es6标准里的三个新方法keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历,这个下次分享es6时在补充介绍了。而在本次的分享里面,filter,some,every我个人认为它们不是真正意义上的循环方法,它们都是为了做特定需求数组处理的,只是它们在功能上面具备了对数组遍历的能力。而我们在对数组做循环处理的时候,我个人推荐使用for循环, for of循环,map(),forEach()这几个为主。本次分享就到这里,谢谢!