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?


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.


215

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


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


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


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)


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


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'


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

1

Vous pouvez essayer ce hack:

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

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.



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]
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.