Destrukturyzacja w celu uzyskania ostatniego elementu tablicy w es6

116

W skrypcie kawowym jest to proste:

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

Czy es6 pozwala na coś podobnego?

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

Oczywiście, że mogę to zrobić w sposób es5 -

const a = b[b.length - 1]

Ale może jest to trochę podatne na jeden błąd. Czy plama może być tylko ostatnią rzeczą w destrukturyzacji?

George Simms
źródło
7
Dlaczego wszyscy myślą, że ES6 zmienia wszystko i jest jakaś nowa składnia do robienia xyz?
Felix Kling
23
@FelixKling pytanie dotyczy w szczególności zachowania ...w es6, w szczególności, że może być użyte tylko jako ostatnia rzecz podczas destrukturyzacji lub na liście parametrów. Jest to potencjalnie sprzeczne z intuicją dla kogoś wchodzącego do es6 z coffeescript, a zatem to pytanie jest potencjalnie przydatne.
George Simms,
Oznacza to, [1,2,3].slice(-1)że poza tym nie możesz nawet zniszczyć odpowiednika [1,2,3].slice(0, -1). To są typowe operacje. Destrukturyzacja ES6 to w jakiś sposób żart!
scriptum
@ Nawet istnieje uzasadniony powód - aby obsługiwać nieskończone iterowalne elementy.
George Simms
Szkoda odpoczynku, ponieważ pierwszy parametr nie działa. Byłoby fajnie ... Oto plik jsperf wykorzystujący niektóre odpowiedzi jsperf.com/destructure-last/1
Shanimal

Odpowiedzi:

46

Nie jest to możliwe w ES6 / 2015. Norma po prostu tego nie przewiduje.

Jak widać w specyfikacji , FormalParameterListmoże to być:

  • za FunctionRestParameter
  • a FormalsList(lista parametrów)
  • a FormalsList, po którym następuje aFunctionRestParameter

Po FunctionRestParameterparametrach nie podano.

Andrey Mikhaylov - lolmaus
źródło
215

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

Ryan Huang
źródło
4
Ładne, proste, niemutacyjne rozwiązanie.
Jack Steam,
1
@Shanimal Depends, otrzymuję popwersję szybciej (OS X, Chrome 68).
Dave Newton,
1
@Dave Newton Ale pop () powoduje mutację
Antonio Pantano
1
@AntonioPantano Tak, modyfikuje kopię. Chodziło o to, czy jest szybsze, czy nie, nie jest pewne.
Dave Newton
53

Uważam, że ES6 może przynajmniej w tym pomóc:

[...arr].pop()

Biorąc pod uwagę, że twoja tablica (arr) nie jest niezdefiniowana i jest elementem iterowalnym (tak, nawet łańcuchy działają !!), powinna zwrócić ostatni element ... nawet dla pustej tablicy i też jej nie zmienia. Tworzy jednak tablicę pośrednią… ale to nie powinno kosztować dużo.

Twój przykład wyglądałby wtedy następująco:

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

buty
źródło
6
uhh, jest dość źle, nawet .slice(-1)[0]jest trochę mniej zły lub var [last]=arr.slice().reverse()jest inny brzydki, jeśli potrzebujesz
caub
6
Myślałem, że ten post dotyczy ES6 / ES2015, nie? Ale szczególnie podoba mi się twój ostatni kawałek. Co powiesz na połączenie tych dwóch var [last] = arr.slice(-1)
:;
13
moim ulubionym sposobem jestObject.defineProperty(Array.prototype, -1, { get() {return this[this.length - 1] } }); [1,2,3][-1]
caub
3
Chociaż to działa, jest mutacją i usuwa element z oryginalnej tablicy. Nie jest idealny w wielu scenariuszach.
GavKilbride
4
@GavKilbride nie. Przykład jest taki sam, jak ten, [].concat(arr).pop();który nie podlega mutacji arr.
Dan
37

Możesz zniszczyć odwróconą tablicę, aby zbliżyć się do tego, co chcesz.

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

KamiOfTea
źródło
2
Mądry. Lepiej niż const last = ['bbb', 'uuu', 'iii'].slice(-1);? Jeśli chodzi o występy?
Vadorequest
1
.slice(-1)jest technicznie szybciej, ale to nie daje zarówno ostatniego punktu, a subarray w jednej rozmowy, co jest zaletą ...ikoną podczas demontażu struktury. Uderzenie w wydajność dwukrotnego cofania należy wziąć pod uwagę, gdy jest używane na dłuższych tablicach, ale dla małego skryptu prawdopodobnie warty wygody? Ale równie łatwo let a = array.slice(-1), rest = array.slice(0,array.length-2)mógłbyś, gdybyś nadal chciał oneliner w ES5, czyli ~ 4% szybciej. jsperf.com/last-array-splat
mix3d
17

inne podejście to:

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

Den Kerny
źródło
1
@isakbob yeap, oto jesteś
Den Kerny
trudne do odczytania, a może to tylko mój mózg
webjay
może być bardzo pomocne używanie wielu rekwizytów, więc tak, to tylko twoje, xd xd xd
Den Kerny
5

Niekoniecznie najbardziej wydajna metoda działania. Ale w zależności od kontekstu dość eleganckim sposobem byłoby:

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

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

theTaoOfJS
źródło
3
Nie widzę elegancji w tym rozwiązaniu, ale i tak @shoesel już to opublikował
Bergi
2

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

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

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

andrhamm
źródło
2
Tak, uważam to za przydatne, gdy robię już inne destrukturyzacje. Samo w sobie nie jest tak łatwe do odczytania, jak klasyczne rozwiązanie.
andrhamm
1

To powinno działać:

const [lastone] = myArray.slice(-1);
OPulido
źródło
1

Możesz spróbować tego hacka:

let a = ['a', 'b', 'program'];
let [last] = a.reverse();
a.reverse();
console.log(last);
Ups Bazaar
źródło
0

Zdecydowanie chodzi o Destrukturyzację dla tablic JavaScript i wiemy, że nie jest możliwe posiadanie ostatniego elementu tablicy przy użyciu przypisania destrukturyzacji, istnieje sposób, aby to zrobić niezmiennie , patrz poniżej:

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

Nie modyfikujemy arrzmiennej, ale nadal mamy wszystkie elementy tablicy z wyjątkiem ostatniego elementu jako tablicę, a ostatni element mamy oddzielnie.

AmerllicA
źródło
0
let a = [1,2,3]
let [b] = [...a].reverse()
Andrew Nekowitsch
źródło
0

Nie niszczący, ale może pomóc. Zgodnie z dokumentacją javascript i metodą odwrotną można spróbować tego:

const reversed = array1.reverse();
let last_item = reversed[0]
Pamela Hdz
źródło