我几天前发布了一个问题,关于如何在不使用concat
或reduce
的情况下展平数组,我得到了一些很好的答案,但我仍然不能完全理解我收到的解决方案。我会尽力理解每一行,也许有人可以指出我的推理错误。
function flatten(array) {
var l = array.length, temp;
while (l--) {
if (Array.isArray(array[l])) {
flatten(array[l]);
temp = array[l].slice();
temp.unshift(1);
temp.unshift(l);
[].splice.apply(array, temp);
}
}
}
var array = [['1', '2', '3'], ['4', '5', ['6'], ['7', '8']]];
flatten(array);
console.log(array);
好的,首先
var l = array.length, temp;
这里l只是2,因此我们的数组长度为2,temp
为2
if (Array.isArray(array[l]))
如果位置1
的数组(因为我们在l
循环中将1
递减while
)确实是一个数组,我们将执行代码的下一部分
flatten(array[l]);
这里我们需要继续,以防我们在数组中嵌套数组
temp = array[l].slice();
因为切片没有参数temp
= array[1]
;所以现在temp = ['4', '5', ['6'], ['7', '8']]]
temp.unshift(1);
在temp的开头添加一个。 (不知道为什么我们这样做,以及为什么排名第一)
temp.unshift(l);
由于l
为1
,我们会在数组的开头添加另一个1
。
现在temp = [1,1,'4', '5', ['6'], ['7', '8']]
[].splice.apply(array, temp)
;好吧,我真的不知道这条线在做什么。我一直在阅读文档,我理解apply
允许我们为this
指定一个值然后我们可以传递一些参数并运行一个函数(对于我看到的例子),但我可以&#39 ;了解这里的用法是什么。加拼接从索引x
中取出y
个元素,那么这些索引是什么?这里splice
没有参数。并且在开头[]
中使用空数组。请帮助我理解我真的很努力!
答案 0 :(得分:1)
所以你的问题是关于代码的这一部分:
temp.unshift(1);
temp.unshift(l);
[].splice.apply(array, temp);
从最后一个语句开始,它在splice
上调用array
,但是以特定的方式。通常你会这样称呼它:
array.splice(l, 1, temp[0], temp[1], ...)
...表示:在l
的索引array
,删除1个元素,然后插入temp[0]
,temp[1]
,...等问题是我们事先并不知道temp
中有多少元素,但仍需要向splice
提供尽可能多的参数。我们不能只将temp
作为参数传递,因为array
会插入一个数组本身的元素,这就是你只是不想要的做。
虽然在ES6中有一个简单的解决方案(见下文),但在ES5中,您可以使用apply
上的splice
来解决此问题。 apply
方法接受将函数应用于的第一个参数,然后是一个包含需要传递给该函数的所有参数的数组。
由于这两个参数中的前两个具有索引的含义,以及要删除的元素数(见上文),然后其余参数表示需要插入哪些元素(temp
中的元素),所有这一切都发生了变化:这些插入了两个第一个参数传递给splice
。
然后剩余的参数是最初在temp
中的变量(在变换之前)。您可以说shift
和apply
语句执行以下操作:
array.splice(temp[0], temp[1], temp[3], temp[4], ...)
注意temp
现在如何为所有参数扮演角色。这就是前两个值被移入的原因。它看起来很复杂,虽然它有效,但它不会产生非常易读的代码。
现在在ES6中,它变得更加简单。您现在可以使用扩展运算符将数组分解为不同的参数,函数可以处理:
array.splice(l, 1, ...temp)
由于我们不再需要转移,我们可以安全地执行此操作而不使用变量temp
,并直接在array[l]
上执行此操作。所以完整的代码看起来像这样:
function flatten(array) {
var l = array.length;
while (l--) {
if (Array.isArray(array[l])) {
flatten(array[l]);
array.splice(l, 1, ...array[l]);
}
}
}
var array = [['1', '2', '3'], ['4', '5', ['6'], ['7', '8']]];
flatten(array);
console.log(array);

不是那么好又简单吗? ; - )
答案 1 :(得分:0)
我认识到来自fcc的挑战......但这是一种非常复杂的方式。这是怎么解决的。
function flatten(arr) {
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
}, []);
}
function steamroller(arr) {
return flatten(arr);
}
steamroller([1, [2], [3, [[4]]]]);
你发布的解决方案是非常复杂,混乱和破碎,最后的解除只是在数组的开头加1,1,这是一个通过挑战的肮脏方式......
答案 2 :(得分:0)
我会这样做这个工作;
var a =[['1', '2', '3'], ['4', '5', ['6'], ['7', ['8','9']]]];
Array.prototype.flat = function(){
return this.reduce((p,c) => Array.isArray(c) ? p.concat(...c).flat() : p.concat(c),[]);
};
var b = a.flat();
console.log(JSON.stringify(b));

答案 3 :(得分:0)
Splice是一个函数,它从索引开始,要删除的元素数量,以及要插入剩余空洞内部的0+元素。
Apply是一个函数有的方法(是的,函数是对象,有方法)。
它需要一个this
,然后需要传入一组参数。
如果您不知道自己有多少元素,但需要将它们全部传递给函数:
// instead of
fn(a, b, c, d, e, f, g);
// you can say
fn.apply(null, args); // args being an array of arbitrary length
所以你可以说:
array.splice.apply(array, args);
其中args应该是索引,要删除的数字,然后是放在该洞内的任意元素列表。
[]
只是一个可以快速访问splice
(通过apply
调用它)的一次性数组。