学习笔记——数组扁平化和apply的使用
背景
背景:我的一个朋友朋友前段时间去面试,回来跟我们分享面经。其中有一道题是:二维数组扁平化。
听到这个题目我的第一想法是递归:
let res_arr = []
let fun = (arr) => {
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
fun(arr[i])
} else {
res_arr.push(arr[i])
}
}
}
fun([[12,21],[1,2,3],[2,3,4]])
朋友的思路也是递归。可是面试官说了一个非常简单的方法,只有一行代码
let aa=[[12,21],[1,2,3],[2,3,4]];
function turn(arr){
return [].concat.apply([],arr); // 就是这行代码
}
console.log('res: ', turn(aa));
这一行代码给我看呆了,给作为小白的我的心灵造成了很大的冲击——还能这样?
于是我就跑去查了查这种写法,总结出了一些自己的理解:
首先是concat(),concat()方法是合并多个数组,但并不会改变当前数组。这么一想是可以用来实现二维数组扁平化。
但是我还是对apply([], arr)中apply第一个参数为空数组比较疑惑,就查询了apply的相关文章和实例,终于是明白了这样写的意义,并作了一些总结
1.apply和call的区别
2.apply中参数的含义
1.apply和call的区别
apply方法接收的参数是一个包含了若干个参数的数组(也正是因为这样,可以用于数组扁平化)
call方法接收的参数是若干个参数列表
比如说:call(this, a, b) 和 apply(this, [a, b])
因此我们可以把二维数组中的每一个值作为参数,通过apply传递
那么我们什么时候用apply什么时候用call呢?
在给对象参数的情况下,如果参数的形式是数组的时候,并且在调用函数的时候参数的列表是对应一致的,比如:
function Person(name, age) {
this.name = name
this.age = age
}
function Xiaoming(name, age) {
Person.apply(this, arguments)
}
let xiaoming = new Xiaoming('xiaoming', 18)
console.log(`name: ${xiaoming.name}, age${xiaoming.age}`)
Person的参数列表和Xiaoming的参数列表都是(name,age),这时就可以采用 apply,如果我的Person的参数列表是这样的(age,name),而Xiaoming的参数列表是(name,age),这样就可以用call来实现了,比如:
function Person(age, name) {
this.name = name
this.age = age
}
function Xiaoming(name, age) {
Person.call(this, age, name)
}
let xiaoming = new Xiaoming('xiaoming', 18)
console.log(`name: ${xiaoming.name}, age${xiaoming.age}, grad${xiaoming.grade}`)
2.apply中参数的含义
这一点总结其实和上一条有些重复
fun.apply(thisArg, [argsArray])
thisArg: 这是在fun函数执行时指定的this值。
argsArray:作为数组传递给fun的参数,其中的每一项都会作为参数单独传递给函数。如果argsArray为null或者undefined,则表示不需要传递任何参数给函数。
可是,为什么在数组扁平化代码中,thisArg要为空数组呢。如果我不写[],我分别试了下Array,this,String
Array
this
String
我发现在新的数组中下标为0的位置都混进了奇奇怪怪的东西,也就是写了谁,谁就是第一个。为什么呢?
由于apply是改变this指向的 所以第一个参数代表的就是本体,其余的所有参数都在thisArg之后存储,如果thisArg本身是有内容的 根据concat连接所以会把剩下的都加在thisArg的后面
举个栗子
let a=[1,2,3],b=[4,5,6];
[].push.apply(a,b);
console.log(a); //1,2,3,4,5,6
console.log(b); //4,5,6
既然是这样,那就把空数组作为第一个参数,就可以完美实现数组扁平化了。
apply的一些别的用法
由实现数组扁平化用到apply这个想法,我们还可以通过apply来实现别的对于数组的一些操作,比如:
let arr = [2,3,1,4,5]
Math.max.apply(null, arr) // 获取数组中最大值 5
Math.min.apply(null, arr) // 获取数组中最小值 1
至于我第一时间想到递归的方法,其中一个原因是我最近在学习二叉树相关的算法,频繁使用了递归。当然我也总结出了一些很容易理解的递归思想,过段时间我会把这段时间刷的二叉树相关的算法整理一下,有兴趣的朋友可以持续关注~~