Desestructurar para obtener el último elemento de una matriz en es6

116

En coffeescript esto es sencillo:

coffee> a = ['a', 'b', 'program']
[ 'a', 'b', 'program' ]
coffee> [_..., b] = a
[ 'a', 'b', 'program' ]
coffee> b
'program'

¿Es6 permite algo similar?

> const [, b] = [1, 2, 3]                              
'use strict'                                           
> b  // it got the second element, not the last one!                      
2                                                      
> const [...butLast, last] = [1, 2, 3]          
SyntaxError: repl: Unexpected token (1:17)                                                                                                                                                        
> 1 | const [...butLast, last] = [1, 2, 3]                                                                                                                                                        
    |                  ^                                                                                                                                                                          
    at Parser.pp.raise (C:\Users\user\AppData\Roaming\npm\node_modules\babel\node_modules\babel-core\node_modules\babylon\lib\parser\location.js:24:13)                                           

Por supuesto que puedo hacerlo de la forma es5 -

const a = b[b.length - 1]

Pero tal vez esto sea un poco propenso a errores de uno. ¿Puede el splat ser lo último en la desestructuración?

George Simms
fuente
7
¿Por qué todo el mundo piensa que ES6 cambia todo y hay una nueva sintaxis para hacer xyz?
Felix Kling
23
@FelixKling la pregunta es en particular sobre el comportamiento de ...en es6, particularmente que solo se puede usar como lo último cuando se desestructura o en una lista de parámetros. Esto es potencialmente contrario a la intuición para alguien que ingresa a es6 desde coffeescript y, por lo tanto, esta pregunta es potencialmente útil.
George Simms
Eso significa que además [1,2,3].slice(-1)no se puede desestructurar equivalente a [1,2,3].slice(0, -1). Estas son operaciones comunes. ¡La desestructuración de ES6 es de alguna manera una broma!
scriptum
@Incluso hay una razón legítima: manejar infinitos iterables.
George Simms
Lástima que el descanso ya que el primer parámetro no funciona. Hubiera sido genial ... Aquí hay un jsperf usando algunas de las respuestas jsperf.com/destructure-last/1
Shanimal

Respuestas:

46

No es posible en ES6 / 2015. El estándar simplemente no lo prevé.

Como puede ver en la especificación , FormalParameterListpuede ser:

  • una FunctionRestParameter
  • a FormalsList(una lista de parámetros)
  • una FormalsList, seguida de unaFunctionRestParameter

FunctionRestParameterNo se proporciona haber seguido los parámetros.

Andrey Mikhaylov - lolmaus
fuente
215

console.log('last', [1, 3, 4, 5].slice(-1));
console.log('second_to_last', [1, 3, 4, 5].slice(-2));

Ryan Huang
fuente
4
Bonita solución simple no mutativa.
Jack Steam
1
@Shanimal Depende, obtengo la popversión más rápida (OS X, Chrome 68).
Dave Newton
1
@Dave Newton Pero pop () causa mutación
Antonio Pantano
1
@AntonioPantano Sí, muta la copia. El punto era si es más rápido o no, no es un hecho.
Dave Newton
53

Creo que ES6 podría al menos ayudar con eso:

[...arr].pop()

Dado que su matriz (arr) no está indefinida y es un elemento iterable (sí, ¡incluso las cadenas funcionan!), Debería devolver el último elemento ... incluso para la matriz vacía y tampoco lo altera. Sin embargo, crea una matriz intermedia ... pero eso no debería costar mucho.

Su ejemplo se vería así:

  console.log(  [...['a', 'b', 'program']].pop() );

zapatos
fuente
6
uhh, es bastante malo, incluso .slice(-1)[0]es un poco menos malo, o var [last]=arr.slice().reverse()es otro feo si lo necesita
caub
6
Pensé que esta publicación era sobre ES6 / ES2015, ¿no? Pero me gusta especialmente tu última pieza. ¿Qué tal combinar los dos var [last] = arr.slice(-1)
:;
13
mi forma favorita esObject.defineProperty(Array.prototype, -1, { get() {return this[this.length - 1] } }); [1,2,3][-1]
caub
3
Aunque esto funciona, es mutativo y elimina el elemento de la matriz original. No es ideal en muchos escenarios.
GavKilbride
4
@GavKilbride no es así. El ejemplo es el mismo [].concat(arr).pop();que no cambia arr.
Dan
37

Puede desestructurar la matriz invertida para acercarse a lo que desea.

const [a, ...rest] = ['a', 'b', 'program'].reverse();
  
document.body.innerHTML = 
    "<pre>"
    + "a: " + JSON.stringify(a) + "\n\n"
    + "rest: " + JSON.stringify(rest.reverse())
    + "</pre>";

KamiOfTea
fuente
2
Inteligente. Mejor que const last = ['bbb', 'uuu', 'iii'].slice(-1);? ¿En términos de actuaciones?
Vadorequest
1
el .slice(-1)es técnicamente más rápido, pero no le brinda tanto el último elemento como el subarreglo en una llamada, lo cual es un beneficio del ...splat al desestructurar. El impacto de rendimiento de invertir dos veces se debe considerar cuando se usa en matrices más largas, pero para un script pequeño, probablemente valga la pena la conveniencia. Pero podría hacerlo con la misma facilidad let a = array.slice(-1), rest = array.slice(0,array.length-2)si aún quisiera el delineador en ES5, eso es ~ 4% más rápido. jsperf.com/last-array-splat
mix3d
17

otro enfoque es:

const arr = [1, 2, 3, 4, 5]
const { length, [length - 1]: last } = arr; //should be 5
console.log(last)

Den Kerny
fuente
1
@isakbob yeap, aquí está
Den Kerny
difícil de leer, o tal vez es solo mi cerebro
webjay
podría ser muy útil usar múltiples accesorios, así que sí, es solo tuyo, xd xd xd
Den Kerny
5

No es necesariamente la forma más eficaz de hacerlo. Pero dependiendo del contexto una forma bastante elegante sería:

const myArray = ['one', 'two', 'three'];
const theOneIWant = [...myArray].pop();

console.log(theOneIWant); // 'three'
console.log(myArray.length); //3

theTaoOfJS
fuente
3
No veo ninguna elegancia en esta solución, pero de todos modos @shoesel ya la publicó
Bergi
2

const arr = ['a', 'b', 'c']; // => [ 'a', 'b', 'c' ]

const {
  [arr.length - 1]: last
} = arr;

console.log(last); // => 'c'

Andrhamm
fuente
2
Sí, lo encuentro útil cuando ya estoy haciendo otras desestructuraciones. Por sí solo, no es tan fácil de leer como la solución clásica.
andrhamm
1

Esto debería funcionar:

const [lastone] = myArray.slice(-1);
OPulido
fuente
1

Puedes probar este truco:

let a = ['a', 'b', 'program'];
let [last] = a.reverse();
a.reverse();
console.log(last);
Bazar de Ups
fuente
0

Definitivamente, la pregunta es sobre Desestructuración para matrices de JavaScript, y sabemos que no es posible tener el último elemento de una matriz usando la asignación de desestructuración, hay una forma de hacerlo inmutable , vea lo siguiente:

const arr = ['a', 'b', 'c', 'last'];

~~~
const arrDepth = arr.length - 1;

const allExceptTheLast = arr.filter( (dep, index) => index !== arrDepth && dep );
const [ theLastItem ] = arr.filter( (dep, index) => index === arrDepth && dep );

No mutamos la arrvariable, pero todavía tenemos todos los miembros de la matriz excepto el último elemento como una matriz y tenemos el último elemento por separado.

AmerllicA
fuente
0
let a = [1,2,3]
let [b] = [...a].reverse()
Andrew Nekowitsch
fuente
0

No es destructivo pero podría ayudar. De acuerdo con la documentación de javascript y el método inverso, podría probar esto:

const reversed = array1.reverse();
let last_item = reversed[0]
Pamela Hdz
fuente