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?


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.


215

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


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() );


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>";


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)


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


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'


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);

1

Puedes probar este truco:

let a = ['a', 'b', 'program'];
let [last] = a.reverse();
a.reverse();
console.log(last);

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.



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]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.