for\forIn\forOf\forEach() 详解


本文旨在简述for for..in for..of forEach()四者作用及区别

for

语法

for (初始表达式; 条件表达式; 最终表达式)
	循环体

说明

  • 作用:用于创建一个循环,它包含了三个可选的表达式,这三个表达式被包围在圆括号之中,使用分号分隔,后跟一个用于在循环中执行的语句(通常是一个块语句)。

  • 初始化表达式:在循环开始前执行一次,通常用来声明并初始化循环变量。

    注:用 varlet 关键字声明新的变量,使用 var 声明的变量不是该循环的局部变量,而是与 for 循环处在同样的作用域中。用 let 声明的变量语句的局部变量。该表达式的结果无意义。

  • 条件表达式:每次循环前检查这个条件,如果为真则继续执行循环体(statement),否则退出循环。

    注:这个表达式是可选的。如果被忽略,那么就被认为永远为真。

  • 最终表达式:在每次循环体执行完毕后被执行,通常用来改变循环变量的值以达到循环控制的目的。

    注:执行时机是在下一次 条件表达式 的计算之前。

  • 循环体:只要condition的结果为 true 就会被执行的语句。

    注:使用一个块语句 { ... } 来包含要执行的语句。如果只有一行语句需要执行可不写 {} 。没有任何语句要执行,使用一个空语句 ;

示例

// 基础示例
for (var i = 0; i < 9; i++) {
  console.log(i);
}
// 单语句执行
for (var i = 0; i < 9; i++) console.log(i);
for (var i = 0; i < 9; i++) 
	console.log(i);
// 初始表达式缺省
var i = 0;
for (; i < 9; i++) {
  console.log(i);
}
// 条件表达式缺省
for (var i = 0; ; i++) {
  console.log(i);
  // 如果省略条件表达式,则必须确保在循环体内跳出,以防创建死循环。
  if (i > 3) break;
}
// 所有表达式缺省
// 同上,确保使用了 break 语句来跳出循环并且还要修改(增加)一个变量,使得 break 语句的条件在某个时候为真
var i = 0;
for (;;) {
  if (i > 3) break;
  console.log(i);
  i++;
}

for…in

语法

for (variable in object) {
  statement
}

说明

  • 作用:以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。
  • variable:在每次迭代时,variable 会被赋值为不同的属性名
  • object:非 Symbol 类型的可枚举属性被迭代的对象。
  • 注:

    1.for…in不应该用于迭代一个关注索引顺序的 Array。
    2.其会遍历手动添加的其他键,甚至包括原型链上的键,只能获得对象的键名,不能直接获取键值,因为它是遍历对象而设计。
    3.如果只考虑对象本身的属性,而不是它的原型,那么使用 getOwnPropertyNames() 或执行 hasOwnProperty() 来确定某属性是否是对象本身的属性。

示例

// 基础示例
var obj = { a: 1, b: 2, c: 3 };
for (var prop in obj) {
  console.log("obj." + prop + " = " + obj[prop]);
}
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"

// 使用hasOwnProperty():继承的属性不显示。
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
let iterable = [3, 5, 7];
iterable.foo = 'hello';
for (let i in iterable) {
	// 由于继承和原型链,对象iterable继承属性objCustom和arrCustom。
	console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (let i in iterable) {
	if (iterable.hasOwnProperty(i)) {
		console.log(i); // 0, 1, 2, "foo"
	}
}

for…of

语法

for (variable of iterable) {
    //statements
}

说明

  • 作用:可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
  • variable:在每次迭代中,将不同属性的值分配给变量。
  • object:被迭代枚举其属性的对象。
  • 注:

对于普通的对象,for…of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用。但是,这样情况下,for…in循环依然可以用来遍历键名。

示例

// 基础示例
const array1 = ['a', 'b', 'c'];
for (const element of array1) {
  console.log(element);
}
// "a" "b" "c"

// 迭代数组
let iterable = [10, 20, 30];
for (let value of iterable) {
  value += 1;
  console.log(value);
}

// 迭代String
let iterable = "boo";
for (let value of iterable) {
  console.log(value);
}
// "b"  "o"  "o"

// 迭代TypedArray(类数组)
let iterable = new Uint8Array([0x00, 0xff]);
for (let value of iterable) {
  console.log(value);
}
// 0  255

// 迭代Map
let iterable = new Map([
  ["a", 1],
  ["b", 2],
  ["c", 3],
]);
for (let entry of iterable) {
  console.log(entry);
}
// ["a", 1] ["b", 2] ["c", 3]

// 迭代Set
let iterable = new Set([1, 1, 2, 2, 3, 3]);
for (let value of iterable) {
  console.log(value);
}
// 1 2 3

// 迭代 arguments 对象
(function () {
  for (let argument of arguments) {
    console.log(argument);
  }
})(1, 2, 3);

// 1 2 3

// 迭代 DOM 集合
// 注意:这只能在实现了 NodeList.prototype[Symbol.iterator] 的平台上运行
// 给每一个 article 标签内的 p 标签添加一个 "read" 类。
let articleParagraphs = document.querySelectorAll("article > p");
for (let paragraph of articleParagraphs) {
  paragraph.classList.add("read");
}

// 对于普通的对象,for...of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用。但是,这样情况下,for...in循环依然可以用来遍历键名
let es6 = {
	edition: 6,
	committee: "TC39",
	standard: "ECMA-262"
};
for (let e in es6) {
	console.log(e);
}
// edition  committee  standard

for (let e of es6) {
	console.log(e);
}
// TypeError: es6[Symbol.iterator] is not a function

forEach()

语法

forEach(callbackFn)
forEach(callbackFn, thisArg)

说明

  • 作用:是一个迭代方法。它按索引升序地为数组中的每个元素调用一次提供的callbackFn 函数。
  • callbackFn:为数组中每个元素执行的函数。并会丢弃它的返回值。
  • thisArg:执行 callbackFn 时用作 this 的值。
  • 注:

    1.forEach() 总是返回 undefined,而且不能继续链式调用。
    2.callbackFn 仅对已赋值的数组索引调用。对于稀疏数组中的空槽,它不会被调用。
    3.除非抛出异常,否则没有办法停止或中断 forEach() 循环。如果有这样的需求,则不应该使用 forEach() 方法。

示例

// 基础示例
const items = ["item1", "item2", "item3"];
const copyItems = [];
items.forEach((item) => {
  copyItems.push(item);
});

总结

for:简单易用,步进可控,节省内存,理解成本低,写起来麻烦;
for…in:为便利对象属性而构建,只推荐在处理有key-value数据(比如属性用作“键”),需要检查其中的任何键是否为某值的情况时使用;
for…of:无需考虑遍历对象长短,步进固定为1;
forEach():为函数形式,·式调用,不可中止,调用时要保证数据类型满足要求,在满足要求时,forEach()最好使。


🎉完结撒花🎉 😁有用吗😁 👍点赞呀👍

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sKK07

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值