👾 笔记 | 类数组与数组扁平化
一、类数组 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 进行累加操作 |
扩展运算符实现 | 普通 | 筛选出数组项进行连接 |
toString 和 split | 简单 | 转成字符串再转数组 |
flat 方法 | 简单 | 特定功能方法直接操作 |
正则和 JSON 方法 | 普通 | JSON 方法转成字符串转回过程中正则处理 |
❧