1️⃣ forEach

该方法是对数组的每个元素执行一次给定的函数;他的返回值是 undefined;

语法

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

参数

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

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

如果 thisArg 参数有值,则每次 callback 函数被调用时,this 都会指向 thisArg 参数。如果省略了 thisArg 参数,或者其值为 null 或 undefined,this 则指向全局对象.

使用

const array1 = ['a', 'b', 'c'];

array1.forEach((item, index, arr) => {
  console.log(item, index, arr)
  // a 0 ["a", "b", "c"]
  // b 1 ["a", "b", "c"]
  // c 2 ["a", "b", "c"]
})

不同点

  • 与 map() 或者 reduce() 不同的是,它总是返回 undefined 值,并且不可链式调用。
  • 不会改变原数组
  • 与 for...of 不同的是他对于空缺的数组单元不进行任何操作;map、for...in 也不会进行操作;
[1,3,,7].forEach(item => console.log(item)) // 1, 3. 7

for(let i in [1,3,,7]) {
  console.log(i) // 0, 1, 3
}

for(let i of [1,3,,7]) {
  console.log(i) // 1, 3, undefined, 7
}
  • 不能使用 breck 跳出循环(报错),使用 return 会跳过本次循环,不会跳出循环(可以在 forEach 代码中使用 return )
const array1 = ['a', 'b', 'c'];

array1.forEach(element => {
  if(element === 'a') {
    return
  }
  console.log(element) // 'b', 'c'
});

针对这个问题可以使用数组的另外两个方法 some() 与 every()

// some():当内部return true时跳出整个循环
const arr = [1,2,3,4,5];
const num = 3;
arr.some(function(v){
   if(v === num) {
       return true;
   }
   console.log(v); // 1, 3, true
});

// every():当内部return false时跳出整个循环
var arr = [1,2,3,4,5];
var num = 3;
arr.every(function(v){
  if(v == num) {
    return false;
  }else{
    console.log(v);
    return true;
  }
});
// 1, 2, false

2️⃣ for...in

for...in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性;可以使用 break 跳出循环;在代码中使用 return 会直接报错;在函数体中使用可以跳出循环。

语法

for (variable in object)
statement

variable
在每次迭代时,variable会被赋值为不同的属性名。
object
非Symbol类型的可枚举属性被迭代的对象。

仅迭代自身的属性

如果你只要考虑对象本身的属性,而不是它的原型,那么使用 getOwnPropertyNames() 或执行 hasOwnProperty() 来确定某属性是否是对象本身的属性(也能使用propertyIsEnumerable)。或者,如果你知道不会有任何外部代码干扰,您可以使用检查方法扩展内置原型。

var triangle = {a: 1, b: 2, c: 3};

function ColoredTriangle() {
  this.color = 'red';
}

ColoredTriangle.prototype = triangle;

var obj = new ColoredTriangle();

for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    console.log(`obj.${prop} = ${obj[prop]}`);
  } 
}

// Output:
// "obj.color = red"

示例

//for in 应用于数组
Array.prototype.sayHello = function(){
    console.log("Hello")
}
Array.prototype.str = 'world';
var myArray = [1,2,10,30,100];
myArray.name='数组';

for(let index in myArray){
    console.log(index);
}
//输出结果如下
// 0,1,2,3,4,name,str,sayHello

//for in  应用于对象中
Object.prototype.sayHello = function(){
    console.log('Hello');
}
Obeject.prototype.str = 'World';
var myObject = {name:'zhangsan',age:100};

for(let index in myObject){
    console.log(index);
}
//输出结果
// name,age,str,sayHello
// 首先输出的是对象的属性名,再是对象原型中的属性和方法,
// 如果不想让其输出原型中的属性和方法,可以使用 hasOwnProperty 方法进行过滤
for(let index in myObject){
    if(myObject.hasOwnProperty(index)){
        console.log(index)
    }
}
//输出结果为
name,age
//你也可以用Object.keys()方法获取所有的自身可枚举属性组成的数组。
Object.keys(myObject)

遍历数组的缺点

可以看出 for in 应用于数组循环返回的是数组的下标和数组的属性和原型上的方法和属性,而 for in 应用于对象循环返回的是对象的属性名和原型中的方法和属性。
使用for in 也可以遍历数组,但是会存在以下问题:

  1. index 索引为字符串型数字,不能直接进行几何运算
  2. 遍历顺序有可能不是按照实际数组的内部顺序
  3. 使用 for in 会遍历数组所有的可枚举属性,包括原型。例如上栗的原型方法 method 和 name 属性

3️⃣ for...of

for...of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
也是不能使用 return ,会报错;在函数体中使用会跳出循环。

不能遍历对象

语法

for (variable of iterable) {
//statements
}

variable
在每次迭代中,将不同属性的值分配给变量。
iterable
被迭代枚举其属性的对象。

示例

// 遍历对象 --报错
Object.prototype.sayHello = function(){
    console.log('Hello');
}
var myObject = {
    name:'zhangsan',
    age:10
}

for(let key of myObject){
    consoloe.log(key); // typeError
}

// 遍历数组
Array.prototype.sayHello = function(){
    console.log("Hello");
}
var myArray = [1,200,3,400,100];
for(let key of myArray){
  console.log(key); // 1, 200, 3, 400, 100
}

// 遍历字符串
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]
}
for (let [key, value] of iterable) {
  console.log(value); // 1 2 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 集合
let articleParagraphs = document.querySelectorAll("article > p");
for (let paragraph of articleParagraphs) {
  paragraph.classList.add("read");
}

跳出循环

对于 for...of 的循环,可以由 break, throw continue 或 return 终止。在这些情况下,迭代器关闭。

与 for...in 的区别

  • for in 遍历的是数组的索引(即键名),而 for of 遍历的是数组元素值。 所以 for in 更适合遍历对象,不要使用 for in 遍历数组。
  • for of 不能遍历对象;
  • for in 可以遍历可迭代对象;包括 Array,Map,Set,String,TypedArray,arguments 对象等等
  • for in 语句以任意顺序迭代对象的可枚举属性。

4️⃣ map

map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值;不能使用 break 跳出循环;使用 return 该项返回为 undefined;
他不会改变原数组。

const array1 = [1, 4, 9, 16];

const map1 = array1.map(x => {
  if(x === 1) {
    return 
  } 
  return x * 2
});

console.log(map1); // [undefined, 8, 18, 32]

语法

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])

参数

callback
生成新数组元素的函数,使用三个参数:
currentValue
callback 数组中正在处理的当前元素。
index可选
callback 数组中正在处理的当前元素的索引。
array可选
map 方法调用的数组。
thisArg可选
执行 callback 函数时值被用作this。

返回值

一个由原数组每个元素执行回调函数的结果组成的新数组。如果你不打算使用返回的新数组,那没必要使用 map 方法,可以使用 foreach 或者 for of 方法。

var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
  return num * 2;
});

// doubles 数组的值为: [2, 8, 18]
// numbers 数组未被修改: [1, 4, 9]

✏️ 补充说明

return 语句就是用于指定函数返回的值。return 语句只能出现在函数体内,出现在代码中的其他任何地方造成语法错误!
但是在 forEach 中,return 并不会报错,在函数体中使用 return,也不会跳出循环;只是跳出本次循环;而在 for in 以及 for of 中会直接跳出循环,如果外层有嵌套 for 循环也会进行终止。

//  return false;  终止循环 如果 for 循环中嵌套了 for 循环也将会终止
//  break;  用于跳出最近的一次循环,如果 for 循环中嵌套了 for 循环嵌套的循环将会继续执行
function mapItem () {
  [1, 2, 3].forEach(item => {
    if (item === 1) {
      return 
    }
    console.log(item) // 2, 3
  })
}

for in 和 for of 会跳出循环

function mapItem () {
  for(let i in [1, 2, 3]) {
    if (i === '1') {
      return
    }
    console.log(i) // 不执行
  }
}

function mapItem () {
  for(let i of [1, 2, 3]) {
    if (i === 1) {
      return
    }
    console.log(i) // 不执行
  }
}