学习笔记——数组扁平化和apply的使用

我心飞翔 分类:javascript

背景

背景:我的一个朋友朋友前段时间去面试,回来跟我们分享面经。其中有一道题是:二维数组扁平化。

听到这个题目我的第一想法是递归:

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

image.png

this

image.png

String

image.png

我发现在新的数组中下标为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
 

至于我第一时间想到递归的方法,其中一个原因是我最近在学习二叉树相关的算法,频繁使用了递归。当然我也总结出了一些很容易理解的递归思想,过段时间我会把这段时间刷的二叉树相关的算法整理一下,有兴趣的朋友可以持续关注~~

回复

我来回复
  • 暂无回复内容