JavaScript—迭代总结

326 阅读4分钟

迭代的起源:工厂函数Iterator

  • 可迭代协议:要想实现可迭代,就必须实现Iterator接口,必须暴露一个属性作为“默认迭代器”,而且这个属性必须使用特殊的Symbol.iterator 作为键。
  • 好在js已经在以下数据类型中为我们实现了Iterator接口
    • 字符串
    • 数组
    • 映射
    • 集合
    • arguments对象
    • NodeList等DOM集合类型 注意!对象并未实现Iterator接口,但对象可通过Object.getOwnPropertyDescriptor(对象, 键名)来获取该对象某个属性的描述对象,该描述对象中有一个属性为enumerable,当该属性为true时,下述操作将忽略掉当前键
    • for...in循环
    • Object.keys()
    • JSON.stringify()
    • Object.assign() image.png
  • 实现了Iterator接口之后我们就可以通过下述方法遍历对应的数据类型了
    • for-of 循环
    • 数组解构
    • 扩展操作符
    • Array.from()
    • 创建集合
    • 创建映射
    • Promise.all()接收由期约组成的可迭代对象
    • Promise.race()接收由期约组成的可迭代对象
    • yield*操作符,在生成器中使用

数组

一、for、for...of

1. for

  • 遍历数组

2. for...of(es6引入)

  • 部署了Symbol.iterator属性就被视为有iterator接口,就可以使用for...of进行遍历
  • for...of可结合keys()、values()、entries()对数组进行遍历,获取键、值、键值对
    // for...of遍历数组
    let arr = [4, 5, 6]
    for (let [index, value] of arr.entries()) {
        console.log(index, value)
    }
    
    // for...of遍历对象
    let obj = {a: 1, b: 2}
    for (let [key, value] of Object.entries(obj)) {
        console.log(key, value)
    }
    // !!!不使用for...of直接用Object.entries也可实现
    

⭐二、es5中的一些方法

forEach()、reduce()、filter()、map()、every()、some()

1. forEach()

  • (1)用途:遍历数组,对数组中的每个元素执行一遍参数方法
  • (2)参数
    • callback必填
      • item:当前元素
      • index:当前元素的索引
      • array:当前数组
    • thisArg可选
  • (3)特点
    • 一旦开始遍历,就无法退出,即所有元素都会被遍历
    • 返回值为undefined
    • 不可链式调用
  • (4)代码
    let arr = [1, 2, 3, 4]
    arr.forEach(item => {
        console.log(item)
    }) 
    

2. reduce()

  • (1)用途:为每一个元素执行一个callback函数
  • (2)参数
    • callback必填
      • prev:上一个循环中return的值(常用)
      • currentValue:当前元素值(常用)
      • currentIndex:当前元素的索引
      • array:当前数组
    • initialValue初始值可选
  • (3)代码
    // 将数组转为对象并用数组中的id作为新对象的key
    let arr = [{id: 1, name: 'a'}, {id: 2, name: 'b'}]
    let obj = arr.reduce((prev, currentValue) => {
        prev[currentValue.id] = currentValue
        return prev
    }, {})
    console.log(obj)
    

3. filter()

  • (1)用途:创建一个新数组,包含通过callback函数的所有元素
  • (2)参数
    • callback回调函数必填
      • item:当前元素值
      • index:当前元素索引
      • array:当前数组
    • thisArg可选
  • (4)返回值:一个由通过callback函数的元素组成的新数组,如果没有任何元素通过,则返回[]
  • (3)代码
    排除小于十的值
    function f(arr) {
        return arr.filter(item => item > 10)
    }
    console.log(f([1, 2, 3, 4, 10, 11, 23, 43]))
    

4. map()

  • (1)用途:创建一个新数组,新数组的元素是原来的数组执行callback函数之后的值
  • (2)参数
    • callback回调函数必填
      • item:当前元素值
      • index:当前元素索引
      • array:当前数组
    • thisArg可选
  • (3)代码
    // [{key: **, value: ''}, {key: **, value: ''}] → [{**: '', **: ''}]
    function format(arr) {
        return arr.map(item => {
            let obj = {}
            obj[item.id] = item.name
            return obj
        })
    }
    console.log(format([{id: 1, name: 'wang'}, {id: 2, name: 'li'}]))
    

5. every()

  • (1)用途:测试数组中的每一个元素通过callback函数后是否为truth值,返回一个布尔值,如果全部通过返回true,否则返回false
  • (2)参数
    • callback回调函数必填
      • item:当前元素值
      • index:当前元素索引
      • array:当前数组
    • thisArg可选
  • (3)特点:不会改变原数组
  • (4)代码
    [1, 2, 4, 11, 34, 23].every(item => item > 10) // false
    

6. some()

  • (1)用途:测试数组中任意一个元素通过callback函数后是否为truth值,返回一个布尔值,如果由一个通过,返回true,全部不通过则返回false
  • (2)参数
    • callback回调函数必填
      • item:当前元素值
      • index:当前元素索引
      • array:当前数组
    • thisArg可选
  • (3)特点:不会改变原数组
  • (4)代码
    [1, 2, 3, 4, 11, 34, 23].some(item => item > 10)  // true
    

⭐三、es6中的一些方法

keys()、values()、entries()

// 结合for...of遍历数组
let arr = [1, 3, 5, 7, 9]
for (let [index, value] of arr.entries()) {
    console.log(index, value)
}

// 使用遍历器的next方法
let arr = [1, 2, 3, 4]
let entries = arr.entries()
console.log(entries.next()) // {value: [0, 1], done: false}
console.log(entries.next()) // {value: [1, 2], done: false}
...
console.log(entries.next()) // {value: undefined, done: true}

对象

一、for...in

  • 遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
  • 缺点:只能获取键名不能获取键值
let obj = {a: '1', b: '2'}
for (let key in obj) {
    console.log(`${key}: ${obj[key]}`)
}

二、es6新增的keys()、values()、entries()

// 结合for...of遍历对象
let obj = {name: 'li', age: 18}
for (let [key, value] of Object.entries(obj)) {
    console.log(key, value)
}

// 直接使用:返回一个数组
let obj = {name: 'zhang', age: 20}
Object.entries(obj)
// [[name, 'zhang'], [age, 20]]

三、Object.getOwnPropertyNames(对象)

let obj = {name: 'zhang', age: 20}
Object.getOwnPropertyNames(obj).forEach(key => console.log(key, obj[key]))
// name zhang
// age 20