Destructuration pour obtenir le dernier élément d'un tableau dans es6

116

Dans coffeescript, c'est simple:

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

ES6 permet-il quelque chose de similaire?

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

Bien sûr, je peux le faire de la manière es5 -

const a = b[b.length - 1]

Mais peut-être que c'est un peu sujet à une erreur. Le splat ne peut-il être que la dernière chose dans la déstructuration?

George Simms
la source
7
Pourquoi tout le monde pense-t-il qu'ES6 change tout et qu'il existe une nouvelle syntaxe pour faire xyz?
Felix Kling
23
@FelixKling la question porte en particulier sur le comportement de ...dans es6, en particulier qu'il ne peut être utilisé que comme dernière chose lors de la déstructuration ou dans une liste de paramètres. Ceci est potentiellement contre-intuitif pour quelqu'un qui entre dans es6 à partir de coffeescript et cette question est donc potentiellement utile.
George Simms
Cela signifie d'ailleurs que [1,2,3].slice(-1)vous ne pouvez même pas déstructurer l'équivalent [1,2,3].slice(0, -1). Ce sont des opérations courantes. La déstructuration ES6 est en quelque sorte une blague!
scriptum
@Même il y a une raison légitime - de gérer des itérables infinis.
George Simms
Dommage que le premier paramètre ne fonctionne pas. Cela aurait été cool ... Voici un jsperf utilisant certaines des réponses jsperf.com/destructure-last/1
Shanimal

Réponses:

46

Ce n'est pas possible dans ES6 / 2015. La norme ne le prévoit tout simplement pas.

Comme vous pouvez le voir dans les spécifications , le FormalParameterListpeut être:

  • une FunctionRestParameter
  • une FormalsList (une liste de paramètres)
  • a FormalsList, suivi d'unFunctionRestParameter

Avoir FunctionRestParametersuivi des paramètres n'est pas fourni.

Andrey Mikhaylov - Lolmaus
la source
215

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

Ryan Huang
la source
4
Belle solution simple et non mutative.
Jack Steam
1
@Shanimal Depends, j'obtiens la popversion la plus rapide (OS X, Chrome 68).
Dave Newton
1
@Dave Newton Mais la pop () cause la mutation
Antonio Pantano
1
@AntonioPantano Oui, il mute la copie. Le point était de savoir si c'est plus rapide ou non n'est pas une évidence.
Dave Newton
53

Je pense que ES6 pourrait au moins vous aider:

[...arr].pop()

Étant donné que votre tableau (arr) n'est pas indéfini et est un élément itérable (oui, même les chaînes fonctionnent !!), il devrait renvoyer le dernier élément .. même pour le tableau vide et il ne le modifie pas non plus. Cela crée cependant un tableau intermédiaire ... mais cela ne devrait pas coûter cher.

Votre exemple ressemblerait alors à ceci:

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

chaussures
la source
6
euh, c'est assez mauvais, c'est même un .slice(-1)[0]peu moins mauvais, ou var [last]=arr.slice().reverse()c'est un autre moche si vous en avez besoin
caub
6
Je pensais que cet article concernait ES6 / ES2015, non? Mais j'aime particulièrement votre dernier morceau. Que diriez-vous de combiner les deux var [last] = arr.slice(-1)
:;
13
ma façon préférée estObject.defineProperty(Array.prototype, -1, { get() {return this[this.length - 1] } }); [1,2,3][-1]
caub
3
Bien que cela fonctionne, il est mutatif et supprime l'élément du tableau d'origine. Pas idéal dans de nombreux scénarios.
GavKilbride
4
@GavKilbride ce n'est pas le cas. L'exemple est le même que celui [].concat(arr).pop();qui ne mute pas arr.
Dan
37

Vous pouvez déstructurer le tableau inversé pour vous rapprocher de ce que vous voulez.

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

KamiOfTea
la source
2
Intelligent. Mieux que const last = ['bbb', 'uuu', 'iii'].slice(-1);? En termes de performances?
Vadorequest le
1
le .slice(-1)est techniquement plus rapide, mais il ne vous donne pas à la fois le dernier élément ET le sous-tableau en un seul appel, ce qui est un avantage du ...splat lors de la déstructuration. L'inversion des performances à deux reprises doit être prise en compte lorsqu'elle est utilisée sur des tableaux plus longs, mais pour un petit script, cela en vaut-il probablement la peine? Mais vous pourriez tout aussi facilement let a = array.slice(-1), rest = array.slice(0,array.length-2)si vous vouliez toujours le oneliner dans ES5, c'est ~ 4% plus rapide. jsperf.com/last-array-splat
mix3d
17

une autre approche est:

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

Den Kerny
la source
1
@isakbob yeap, vous voilà
Den Kerny
difficile à lire, ou peut-être que c'est juste mon cerveau
webjay
il pourrait être très utile d'utiliser plusieurs accessoires, alors oui, c'est juste le vôtre, xd xd xd
Den Kerny
5

Pas nécessairement la manière la plus performante de faire. Mais selon le contexte, une manière assez élégante serait:

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

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

theTaoOfJS
la source
3
Je ne vois aucune élégance dans cette solution, mais de toute façon @shoesel l'a déjà postée
Bergi
2

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

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

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

andrhamm
la source
2
Oui, je trouve cela utile lorsque je fais déjà d'autres déstructuration. En soi, il n'est pas aussi facile à lire que la solution classique.
andrhamm
1

Cela devrait fonctionner:

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

Vous pouvez essayer ce hack:

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

Décidément, la question concerne la destruction des tableaux JavaScript, et nous savons qu'il n'est pas possible d'avoir le dernier élément d'un tableau en utilisant l'affectation de déstructuration, il existe un moyen de le faire immuable , voir ce qui suit:

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

Nous ne modifions pas la arrvariable mais avons toujours tous les membres du tableau sauf le dernier élément en tant que tableau et avons le dernier élément séparément.

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

Pas de manière destructrice mais pourrait aider. Selon la documentation javascript et la méthode inverse, essayez ceci:

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