笔记 | 类数组与数组扁平化

发布时间 2023-08-08 10:07:00作者: iNSlog

一、类数组 Array-like

在日常中能接触到的类数组有这么几个:

  • 参数对象 arguments;

  • 通过 querySelector 获取的 NodeList; NodeList 对象是节点集合,NodeList 可以使用 for...of 来迭代,在一些情况下,NodeList 是一个实时合集;

  • 通过函数:

    • getElementsByTagName
    • getElementsByClassName
    • getElementsByName

    获得的 HTMLCollection;HTMLCollection 是一个 HTML DOM 对象的一个接口,这个接口包含了获取的 DOM 元素集合,返回的是一个类数组对象(Array-like object)。

1. 参数对象 arguments

  • 先看一下 arguments 的各种信息

// arguments
function foo() {
    console.log(arguments) // [Arguments] { '0': 'iNSlog', '1': 123, '2': true }
    console.log(typeof arguments) // object
    console.log(Object.prototype.toString.call(arguments)) // [object Arguments]
    console.log(arguments.callee) // [Function: foo]
}
foo('iNSlog', 123, true)
  • 遍历参数操作

// 遍历参数操作
function add() {
    let sum = 0
    let len = arguments.length
    for (let i = 0; i < len; i++) {
        sum += arguments[i]
    }
    return sum
}
console.log(add()) // 0
console.log(add(1)) // 1
console.log(add(1, 2)) // 3
console.log(add(1, 2, 3, 4)) // 10
  • 自定义连接字符串函数

// 自定义连接字符串函数
function myConcat(s) {
    let args = Array.prototype.slice.call(arguments, 1)
    return args.join(s)
}
let string = myConcat(',', 'a', 'b', 'c')
console.log(string) // a,b,c
string = myConcat(';', 'a', 'b', 'c')
console.log(string) // a;b;c
string = myConcat('.', '1', '2', '3', '4', '5')
console.log(string) // 1.2.3.4.5
  • 传递参数使用

// 传递参数使用
function foo() {
    fooPrint.call(this, ...arguments)
    fooPrint.apply(this, arguments)
}
function fooPrint(a, b, c) {
    console.log(a, b, c)
}
foo(1, 2, 3) // 1 2 3

2. 类数组借用数组方法

先定义一个类数组:

const arrayLike = {
    0: 'a',
    1: 'b',
    2: 'c',
    3: 'd',
    length: 4
}
arrayLike.map((item)=>{ // arrayLike.map is not a function
    console.blog(item)
})
  • 借用数组的一些方法,以及将类数组转化为数组

// 借用数组的 map 方法
Array.prototype.map.call(arrayLike, (item) => {
    console.log(item) // a b c d
})

// 借用数组的 push 方法
Array.prototype.push.call(arrayLike, 'e', 'f')
Array.prototype.map.call(arrayLike, (item) => {
    console.log(item) // a b c d e f
})

// 借用数组的 reverse 方法
let test = []
test.reverse.call(arrayLike)
test.map.call(arrayLike, (item) => {
    console.log(item) // f e d c b a
})

// 快速求和
function sumAll() {
    let args = [].slice.call(arguments)
    return args.reduce((p, v) => p + v)
}
console.log(sumAll(1, 2, 3, 4, 5, 6, 7, 8, 9)) // 45

// ES6 类数组转换成数组的方法 Array.from
const arrLikeToArray = Array.from(arrayLike) // const arrLikeToArray: string[]
console.log(arrLikeToArray.reverse()) // [ 'a', 'b', 'c', 'd', 'e', 'f' ]

3. 类数组总结

自带方法 length 属性 callee 属性
数组 有多个 ×
类数组 ×

二、数组的扁平化

数组的扁平化:将一个嵌套多层的数组转化为只有一层的数组。例如:

[1, [2, [3, [4, 5],6]]] -> [ 1, 2, 3, 4, 5, 6 ]

0. 先定义一个数组

const array = [1, [2, [3, [4, 5], 6]]]

1. 使用递归

function flatten(arr) {
    let result = []
    for (let i = 0; i < arr.length; i++) {
        if (Array.isArray(arr[i])) {
            result = result.concat(flatten(arr[i]))
        } else {
            result.push(arr[i])
        }
    }
    return result
}
console.log(flatten(array)) // [ 1, 2, 3, 4, 5, 6 ]

2. 利用 reduce 方法迭代

function myReduce(arr) {
    return arr.reduce(function (p, v) {
        return p.concat(Array.isArray(v) ? myReduce(v) : v)
    }, [])
}
console.log(myReduce(array)) // [ 1, 2, 3, 4, 5, 6 ]

3. 使用扩展运算符 ...

function flatten(arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}
console.log(flatten(array)) // [ 1, 2, 3, 4, 5, 6 ]

4. 使用 toString 和 split 方法,共同处理

function flatten(arr) {
    return arr.toString().split(',')
}
console.log(flatten(array)) // [ '1', '2', '3', '4', '5', '6' ] 变成字符数组了

5. 调用 ES6 中的 flat 方法

function flatten(arr) {
    return arr.flat(Infinity)
}
console.log(flatten(array)) // [ 1, 2, 3, 4, 5, 6 ]

6. 使用正则表达式过滤,然后调用 JSON 的方法共同处理

function flatten(arr){
    let str = JSON.stringify(arr)
    str = str.replace(/(\[|\])/g, '') // 过滤掉字符串中的 方括号[]
    str = '[' + str + ']'
    return JSON.parse(str)
}
console.log(flatten(array)) // [ 1, 2, 3, 4, 5, 6 ]

7. 数组扁平化总结

方法/问题 实现难度 编码思路
递归实现 简单 递归实现,返回新数组
reduce 实现 普通 reduce 进行累加操作
扩展运算符实现 普通 筛选出数组项进行连接
toStringsplit 简单 转成字符串再转数组
flat 方法 简单 特定功能方法直接操作
正则和 JSON 方法 普通 JSON 方法转成字符串转回过程中正则处理