背景
- 昨天群里面有人发了一道二维数组扁平使用的方法,我感觉特别有意思,给各位看看。
var arr=[[1,2,3],[4,5,6],[7,8,9]]
var arr2=Function.prototype.apply.call(Array.prototype.concat,[],arr);
console.log(arr2);
输出:
[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
于是我就研究了一下到底是怎么个回事。
首先说一下apply和call
- apply和call的区别主要就在第二个参数上,apply第二个参数是数组,call后面可以跟一堆东西当参数。
- 我在百度时候发现有些博客里说
Function.prototype.apply.call
等于Function.prototype.call.call
,在这题里面换一下看看就发现明显不对,结果不一样。我后来发现实际上就是写博客的这人不知道apply这种特殊性质。如果提供给apply的参数是个二维数组,且二维数组里的一维没有除了数组以外的元素,那么apply就可以直接把二维数组里的东西取出来,至于取出来东西是数组还是别的东西,apply不会继续往下取了。 - 所以从上一段描述来看,apply扁平的二维数组很有限,而且算是特例中的特例了。
- 猜想apply的特性是因为页面中去除标签很容易导致提取出二维数组的存在而做的适配。
再解释一下运行过程
- 这个
Function.prototype.apply.call(Array.prototype.concat,[],arr)
其实就可以看成function-apply.call(function-concat,[],arr)
,也就是等于function-concat.function-apply([],arr)
。function-concat
实际是个array的方法,那么按照包装类继承原则,可以把function-concat
替换为[].concat
,再看apply,原题目是在Function.prototype
下拿的apply,同理根据包装类继承原则,concat实际上是个函数,函数的__proto__
也就是老爸,就是Function,那么concat继承了老爸的特性它必然有apply这个方法。最后这个就可以看成[].concat.apply([],arr)
。是不是比Function.prototype.apply.call(Array.prototype.concat,[],arr)
简短多了,一个明明很简单就能写出来效果一样的东西还非要舍近求远一下。