JavaScript novato aquí. Hoy aprendí acerca de reduce y me propuse implementar mi propia función de aplanar matriz.

Lo que tuve fue

var array = [[1, 2], [3, 4, 5], [6]];
var result = array.reduce(Array.prototype.concat, []); // Causes Uncaught TypeError: Array.prototype.concat called on null or undefined
var result = array.reduce(Array.prototype.concat.call, []); // Causes Uncaught TypeError: undefined is not a function

Mientras que las respuestas en ¿Combinar / aplanar una matriz de matrices en JavaScript? son elegantes e idiomáticos, realmente agradecería una ilustración de cómo fallaron mis intentos.

4
Mengchen Yu 17 feb. 2017 a las 08:20

3 respuestas

La mejor respuesta

Tienes la idea correcta con Array.prototype.concat.call. Con Array.prototype.concat, las llamadas se verán así:

var concat = Array.prototype.concat;

concat(concat(concat([],
                     [1, 2]),
              [3, 4, 5]),
       [6])

Que no funciona porque Array.prototype.concat concatena sus argumentos con su this; llamarlo como concat() le da un this de undefined. ¿Qué tal con call?

var call = Array.prototype.concat.call;

call(call(call([],
               [1, 2]),
          [3, 4, 5]),
     [6])

Esto se encuentra con el mismo problema, pero con Function.prototype.call (Array.prototype.concat es una función como cualquier otra, y hereda su método call de Function.prototype). call intenta llamar a su this, pero llamarlo como call() le da un this de undefined.

Puede pasar Function.prototype.call.bind(Array.prototype.concat) ... si reduce no llama a su función con más argumentos que solo el acumulador y el elemento actual. Pero lo hace, pasando el índice del elemento actual y la matriz de contexto también, y arruinando cualquier posibilidad de hacer que esto funcione al pasar solo Array.prototype.concat envuelto con algunas incorporaciones.

2
Ry- 17 feb. 2017 a las 05:32

Esto es así porque Array.prototype.concat requiere un prototipo de función tal que sea una matriz o una lista de valores que se concatenen con la matriz principal.

Sin embargo, la devolución de llamada a Array.prototype.reduce requiere un accumulator, currentValue, currentIndex y array como parámetros.

Los parámetros (así como lo que se supone que deben hacer) no coinciden y, por lo tanto, obtienes resultados o errores inesperados.

0
Blaze Sahlzen 17 feb. 2017 a las 05:30

Tu código es equivalente a

result = array.reduce(fn, []);
function fn(a, b, index, array) { // this is the arguments reduce sends to the callback
    return Array.prototype.concat.call(null, a, b, index, array);
}

¿Puedes detectar el problema?

4
Jaromanda X 17 feb. 2017 a las 05:29