for、for-in、for-of、forEach的区别

总结

for..of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合.但是不能遍历对象,因为没有迭代器对象.与forEach()不同的是,它可以正确响应break、continue和return语句。

for-of循环不支持普通对象,但如果你想迭代一个对象的属性,你可以用for-in循环(这也是它的本职工作)或内建的Object.keys()方法。

for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值。for of遍历的只是数组内的元素,而不包括数组的原型属性method和索引name。

forEach(value,index,Array)不能同时遍历多个集合,在遍历的时候无法修改和删除集合数据,方法不能使用break,continue语句跳出循环,或者使用return从函数体返回,对于空数组不会执行回调函数。

forEach与for当循环遍历为空的数组时,forEach会跳过为空的值,for不会跳过为空的数据,会直接显示undefined。两者都能识别出NULL。

forEach() 被调用时,不会改变原数组,也就是调用它的数组(尽管 callback 函数在被调用时可能会改变原数组)。


具体区别如下:

FOR

var arrList = [1,2,3,4,5,6]
for(var i = 0;i < arrList.length ; i++){
    console.log(arrList[i]);
}

FOR-IN

语法

for (variable in object)
  statement
  • variable

    在每次迭代时,variable会被赋值为不同的属性名。

  • object

    非Symbol类型的可枚举属性被迭代的对象。

描述

for...in 循环只遍历可枚举属性(包括它的原型链上的可枚举属性)。ArrayObject使用内置构造函数所创建的对象都会继承自Object.prototypeString.prototype的不可枚举属性,例如 StringindexOf() 方法或 ObjecttoString()方法。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性(更接近原型链中对象的属性覆盖原型属性)。

举例

/*
	FOR..IN语句遍历数组
*/
Array.prototype.method=function(){
  console.log(this.length);
}
var myArray=[1,2,4]
myArray.name="数组"
for (var index in myArray) {
  console.log(myArray[index]);
}
/*
	输出结果顺序不唯一。输出的结果包含如下:
	1 
	2 
	4 
	数组
	ƒ (){
  	console.log(this.length);
	}
*/
/*
	FOR..IN语句遍历对象
*/
Object.prototype.method=function(){
  console.log(this);
}
var myObject={
  a:1,
  b:2,
  c:3
}
for (var key in myObject) {
  console.log(key);
}
/*
	输出结果顺序不唯一。输出的结果包含如下:
	a 
	b
	c 
	method
	
	1- for in 可以遍历到myObject的原型方法method,如果不想遍历原型方法和属性的话,可以在循环内部判断一		下,hasOwnPropery方法可以判断某属性是否是该对象的实例属性.
	2- 通过ES5的Object.keys(myObject)获取对象的实例属性组成的数组,不包括原型方法和属性.
*/

for (var key in myObject) {
  if(myObject.hasOwnProperty(key)){
    console.log(key);
  }
}
/*
	输出结果顺序不唯一。输出的结果包含如下:
	a 
	b
	c 
*/

注意事项

  • FOR..IN语句遍历的是索引index(键名)为字符串型数字,不能直接进行几何运算。

  • 遍历顺序有可能不是按照实际数组的内部顺序。FOR..IN语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性。

  • 使用for in会遍历数组所有的可枚举属性,包括原型。例如上述案例的原型方法method和name属性,所以for in更适合遍历对象,不要使用for in遍历数组。

删除,添加或者修改属性

for...in 循环以任意序迭代一个对象的属性(请参阅delete运算符,了解为什么不能依赖于迭代的表面有序性,至少在跨浏览器设置中)。如果一个属性在一次迭代中被修改,在稍后被访问,其在循环中的值是其在稍后时间的值。一个在被访问之前已经被删除的属性将不会在之后被访问。在迭代进行时被添加到对象的属性,可能在之后的迭代被访问,也可能被忽略。

通常,在迭代过程中最好不要在对象上进行添加、修改或者删除属性的操作,除非是对当前正在被访问的属性。这里并不保证是否一个被添加的属性在迭代过程中会被访问到,不保证一个修改后的属性(除非是正在被访问的)会在修改前或者修改后被访问,不保证一个被删除的属性将会在它被删除之前被访问。

FOR-OF

for...of语句可迭代对象(包括 ArrayMapSetStringTypedArrayarguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。不建议遍历原有的原生对象。

语法

for (variable of iterable) {
    //statements
}
  • variable

    在每次迭代中,将不同属性的值分配给变量。

  • iterable

    被迭代枚举其属性的对象。

示例

/*
	FOR..OF语句遍历数组
*/
var myArray=[1,2,4,5,6,7,8]
for (var index of myArray) {
  console.log(index);
}
/*
	输出结果顺序唯一。输出的结果如下:
	1
	2
	4
	5
	6
	7
	8
*/

FOREACH

语法

arr.forEach(callback(currentValue [, index [, array]])[, thisArg]);

参数

  • callback

    为数组中每个元素执行的函数,该函数接收三个参数:currentValue数组中正在处理的当前元素。index 可选数组中正在处理的当前元素的索引。array 可选forEach() 方法正在操作的数组。

  • thisArg 可选

    可选参数。当执行回调函数 callback 时,用作 this 的值。

返回值

undefined

描述

forEach() 方法按升序为数组中含有效值的每一项执行一次 callback 函数,那些已删除或者未初始化的项将被跳过(例如在稀疏数组上)。

举例

/*
	数组中未定义或者undefined数据的情况。
*/
const arraySparse = [1,3,,7];
let forCallbackRuns = 0;
let forEachCallbackRuns = 0;

arraySparse.forEach(function(element){
  console.log(element);
  forEachCallbackRuns++;
});

console.log("forEachCallbackRuns: ", forEachCallbackRuns);

/*
1
3
7
numCallbackRuns: 3
*/


for(var i = 0; i < arraySparse.length ; i++){
  console.log(arraySparse[i]);
  forCallbackRuns++;
}
console.log("forCallbackRuns: ", forCallbackRuns);

/*
1
3
undefined
7
forCallbackRuns:  4
*/

/*
	数组中含有null数据的情况。
*/
const arraySparse = [1,3,null,7];
let forCallbackRuns = 0;
let forEachCallbackRuns = 0;

arraySparse.forEach(function(element){
  console.log(element);
  forEachCallbackRuns++;
});

console.log("forEachCallbackRuns: ", forEachCallbackRuns);

/*
1
3
null
7
forEachCallbackRuns:  4
*/


for(var i = 0; i < arraySparse.length ; i++){
  console.log(arraySparse[i]);
  forCallbackRuns++;
}
console.log("forCallbackRuns: ", forCallbackRuns);

/*
1
3
null
7
forCallbackRuns:  4
*/

注意

除了抛出异常以外,没有办法中止或跳出 forEach() 循环。如果你需要中止或跳出循环,forEach() 方法不是应当使用的工具。

若你需要提前终止循环,你可以使用:

这些数组方法则可以对数组元素判断,以便确定是否需要继续遍历:

译者注:只要条件允许,也可以使用 filter() 提前过滤出需要遍历的部分,再用 forEach() 处理。

参考资料链接

作者:Haiya_32ef 链接:https://www.jianshu.com/p/c43f418d6bf0

作者:weixin_34128411 链接:https://blog.csdn.net/weixin_34128411/article/details/94279246

posted @ 2020-01-07 10:17  Scok  阅读(2893)  评论(0编辑  收藏  举报