导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

常规遍历

准备数据

let arr = [
  {
    name: 'Lance',
    age: 27
  },
  {
    name: 'GC',
    age: 30
  },
  {
    name: 'Jerry',
    age: 28
  }
]
// 给 arr 原型上加属性
arr.__proto__["12"] = {
  name: 'Sherry',
  age: 25
}
arr.__proto__["13"] = {
  name: 'Summer',
  age: 27
}
Object.defineProperty(arr.__proto__, '14', {
  value: {
    name: 'Elephant',
    age: 34
  },
  enumerable: true, // 使其可枚举
})

标准 for 循环

for (let i = 0; i < arr.length; i++) {
  let item = arr[i];
  if (item.name === 'GC') break;
  console.log(item);
}
// 打印完 { name: 'Lance', age: 27 } 就退出

for-in 遍历对象

for (const key in arr) {
  let item = arr[key];
  if (item.name === 'Elephant') break;
  console.log(item);
}

// 顺序:1. 自身属性(1.1 整数属性 1.2 其他按创建顺序) 2. 原型链属性(小步骤同自身属性)
// { name: 'Lance', age: 27 }
// { name: 'GC', age: 30 }
// { name: 'Jerry', age: 28 }
// { name: 'Sherry', age: 25 }
// { name: 'Summer', age: 27 }
var obj = {
  name: 'Lance',
  "1": "1",
  "2": "2",
  age: 27
}
obj.__proto__.aa = "aa";
obj.__proto__["22"] = "22";
obj.__proto__["11"] = "11";

for (const key in obj) {
  console.log(key, obj[key]);
}

// 打印
// 1 1
// 2 2
// name Lance
// age 27
// 11 11
// 22 22
// aa aa

⭐️ forEach

// 跳出本次循环
arr.forEach((cur, idx, arr) => {
  if (cur.name === 'GC') return;
  console.log(cur);
});
// 打印
// { name: 'Lance', age: 27 }
// { name: 'Jerry', age: 28 }

// try-catch + throw Error 退出循环
try {
  arr.forEach((cur, idx, arr) => {
    if (cur.name === 'GC') throw new Error('退出循环');
    console.log(cur);
  });
} catch (err) {
  console.log(err);
}
// 打印
// { name: 'Lance', age: 27 }
// Error: 退出循环

// 总是返回 undefined
const ret = arr.forEach((cur, idx, arr) => {
  if (cur.name === 'GC') return '123';
  console.log(cur);
  return '321';
});
console.log(ret); // undefined

for-of 遍历可迭代对象

for (const value of arr) {
  if (value.name === 'GC') break;
  console.log(value);
}
// { name: 'Lance', age: 27 }

ES5 遍历

// arr.reduce(function(total, currentValue, currentIndex, arr), initialValue)
// callback 参数
// (累积器, 当前元素, 当前元素索引, 当前数组)
// initialValue:指定第一次回调 的第一个参数
var wallets = [4, 7.8, 3]
var totalMoney = wallets.reduce(function (countedMoney, curMoney) {
    return countedMoney + curMoney;
}, 0)
var arr = [2, 3, 4, 5, 6]
var morearr = arr.filter(function (number) {
    return number > 3
}) // [4,5,6]
var arr = [1,2,3,4,5]
var result = arr.every(function (item, index) {
    return item > 2
}) // false

console.log([].every(v => v === undefined)); // true
console.log([].every(v => v === 'something')); // true
// some(callback, thisArg)
// callback:
//  	(当前元素, 当前索引, 调用some的数组)

var arr = [1,2,3,4,5]
var result = arr.some(function (item,index) {
    return item > 3
}) // true

console.log([].some(v => v === undefined)); // false
console.log([].some(v => v === 'something')); // false

ES6 遍历

// 语法
let new_array = arr.find(function(currentValue, index, arr), thisArg)
let new_array = arr.findIndex(function(currentValue, index, arr), thisArg)

// 这两个方法都可以识别NaN,弥补了 indexOf 的不足

// find
let a = [1, 4, -5, 10].find((n) => n < 0); // 返回元素 -5
let b = [1, 4, -5, 10, NaN].find((n) => Object.is(NaN, n));  // 返回元素 NaN
// findIndex
let a = [1, 4, -5, 10].findIndex((n) => n < 0); // 返回索引 2
let b = [1, 4, -5, 10, NaN].findIndex((n) => Object.is(NaN, n));  // 返回索引 4
// 语法
array.keys()   array.values()   array.entries()

for (let index of ['a', 'b'].keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);
}
// 0 "a"
// 1 "b"

⭐️ 不要轻易在 forEach 中改变当前遍历元素本身

forEach 如果数组在迭代时被修改了,则其他元素会被跳过。

下面的例子会输出 "one", "two", "four"。当到达包含值 "two" 的项时,整个数组的第一个项被移除了,这导致所有剩下的项上移一个位置。因为元素 "four" 正位于在数组更前的位置,所以 "three" 会被跳过。 forEach() 不会在迭代之前创建数组的副本。

var words = ['one', 'two', 'three', 'four'];
words.forEach(function(word) {
  console.log(word);
  if (word === 'two') {
    words.shift();
  }
});
// one
// two
// four