Destrukturierung, um das letzte Element eines Arrays in es6 zu erhalten

115

In Coffeescript ist dies unkompliziert:

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

Erlaubt es6 etwas Ähnliches?

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

Natürlich kann ich es auf die es5-Art machen -

const a = b[b.length - 1]

Aber vielleicht ist dies ein bisschen anfällig für einen Fehler. Kann der Splat nur das Letzte in der Destrukturierung sein?

George Simms
quelle
7
Warum glaubt jeder, dass ES6 alles ändert und es eine neue Syntax für xyz gibt?
Felix Kling
23
@FelixKling Die Frage bezieht sich insbesondere auf das Verhalten von ...in es6, insbesondere darauf, dass es nur als letztes bei der Destrukturierung oder in einer Parameterliste verwendet werden kann. Dies ist möglicherweise nicht intuitiv für jemanden, der von coffeescript zu es6 kommt, und daher ist diese Frage möglicherweise nützlich.
George Simms
Das heißt außerdem, dass [1,2,3].slice(-1)Sie nicht einmal gleichwertig zerstören können [1,2,3].slice(0, -1). Dies sind übliche Operationen. ES6-Destrukturierung ist irgendwie ein Witz!
Scriptum
@ Auch wenn es einen legitimen Grund gibt - mit unendlichen Iterablen umzugehen.
George Simms
Schade, da der erste Parameter nicht funktioniert. Wäre cool gewesen ... Hier ist ein jsperf mit einigen der Antworten jsperf.com/destructure-last/1
Shanimal

Antworten:

46

In ES6 / 2015 ist dies nicht möglich. Der Standard sieht das einfach nicht vor.

Wie Sie in der Spezifikation sehen können , FormalParameterListkann dies entweder sein:

  • ein FunctionRestParameter
  • a FormalsList(eine Liste von Parametern)
  • a FormalsList, gefolgt von aFunctionRestParameter

Das Befolgen FunctionRestParametervon Parametern wird nicht bereitgestellt.

Andrey Mikhaylov - lolmaus
quelle
215

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

Ryan Huang
quelle
4
Schöne einfache nicht mutative Lösung.
Jack Steam
1
@Shanimal Abhängig davon bekomme ich die popVersion so schnell wie möglich (OS X, Chrome 68).
Dave Newton
1
@ Dave Newton Aber Pop () verursachen Mutation
Antonio Pantano
1
@AntonioPantano Ja, die Kopie wird mutiert. Der Punkt war, ob es schneller ist oder nicht, ist nicht selbstverständlich.
Dave Newton
52

Ich glaube, ES6 könnte zumindest dabei helfen:

[...arr].pop()

Da Ihr Array (arr) nicht undefiniert ist und ein iterierbares Element (ja, sogar Zeichenfolgen funktionieren !!), sollte es das letzte Element zurückgeben ... auch für das leere Array, und es ändert es auch nicht. Es wird zwar ein Zwischenarray erstellt, aber das sollte nicht viel kosten.

Ihr Beispiel würde dann so aussehen:

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

Schuhsel
quelle
6
äh, es ist ziemlich schlimm, ist sogar etwas .slice(-1)[0]weniger schlimm oder var [last]=arr.slice().reverse()ist eine andere hässliche, wenn Sie brauchen
Caub
6
Ich dachte, dieser Beitrag handelt von ES6 / ES2015, nein? Aber ich mag besonders dein letztes Stück. Wie wäre es mit der Kombination der beiden : var [last] = arr.slice(-1);)
Shoesel
13
Mein Lieblingsweg istObject.defineProperty(Array.prototype, -1, { get() {return this[this.length - 1] } }); [1,2,3][-1]
Caub
3
Obwohl dies funktioniert, ist es mutativ und entfernt das Element aus dem ursprünglichen Array. In vielen Szenarien nicht ideal.
GavKilbride
4
@ GavKilbride tut es nicht. Beispiel ist das gleiche wie [].concat(arr).pop();das, das nicht mutiert arr.
Dan
37

Sie können das umgekehrte Array zerstören, um sich dem zu nähern, was Sie möchten.

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

KamiOfTea
quelle
2
Clever. Besser als const last = ['bbb', 'uuu', 'iii'].slice(-1);? In Bezug auf Leistungen?
Vadorequest
1
Das .slice(-1)ist technisch schneller, aber es gibt Ihnen nicht sowohl das letzte Element als auch das Subarray in einem Aufruf, was ein Vorteil des ...Splat bei der Destrukturierung ist. Ein Leistungseinbruch durch zweimaliges Umkehren ist bei Verwendung auf längeren Arrays zu berücksichtigen, aber für ein kleines Skript ist es wahrscheinlich die Bequemlichkeit wert? Aber Sie könnten genauso gut, let a = array.slice(-1), rest = array.slice(0,array.length-2)wenn Sie immer noch den Oneliner in ES5 wollen, das ist ~ 4% schneller. jsperf.com/last-array-splat
mix3d
16

Ein anderer Ansatz ist:

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

Den Kerny
quelle
1
@isakbob yeap, hier sind Sie
Den Kerny
schwer zu lesen, oder vielleicht ist es nur mein Gehirn
Webjay
Es könnte sehr hilfreich sein, mehrere Requisiten zu verwenden, also ja, es liegt nur bei Ihnen, xd xd xd
Den Kerny
5

Nicht unbedingt die performanteste Art zu tun. Aber je nach Kontext wäre ein ziemlich eleganter Weg:

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

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

theTaoOfJS
quelle
3
Ich sehe keine Eleganz in dieser Lösung, aber trotzdem hat @shoesel sie bereits gepostet
Bergi
2

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

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

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

andrhamm
quelle
2
Ja, ich finde es nützlich, wenn ich bereits andere Destrukturierungen vornehme. An sich ist es nicht so einfach zu lesen wie die klassische Lösung.
Andrhamm
1

Das sollte funktionieren:

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

Sie können diesen Hack versuchen:

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

Auf jeden Fall, die Frage ist Destrukturierung für JavaScript - Arrays, und wir wissen , dass es nicht möglich ist , das letzte Element eines Arrays zu haben , durch die Destrukturierung Zuordnung verwendet, gibt es eine Möglichkeit , es zu tun , unveränderlich , finden Sie im folgenden:

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

Wir mutieren die arrVariable nicht, haben aber immer noch alle Array-Mitglieder außer dem letzten Element als Array und haben das letzte Element separat.

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

Nicht zerstörend, könnte aber helfen. Laut Javascript-Dokumentation und umgekehrter Methode könnte dies versucht werden:

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