Destructuring to get the last element of an array in es6

123,642

Solution 1

It is not possible in ES6/2015. The standard just doesn't provide for it.

As you can see in the spec, the FormalParameterList can either be:

  • a FunctionRestParameter
  • a FormalsList (a list of parametes)
  • a FormalsList, followed by a FunctionRestParameter

Having FunctionRestParameter followed by parameters is not provided.

Solution 2

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

Solution 3

I believe ES6 could at least help with that:

[...arr].pop()

Given your array (arr) is not undefined and an iterable element (yes, even strings work!!), it should return the last element..even for the empty array and it doesn't alter it either. It creates an intermediate array though..but that should not cost much.

Your example would then look like this:

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

Solution 4

You can destructure the reversed array to get close to what you want.

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

Solution 5

another approach is:

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

Share:
123,642
George Simms
Author by

George Simms

Updated on February 12, 2022

Comments

  • George Simms
    George Simms over 2 years

    In coffeescript this is straightforward:

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

    Does es6 allow for something 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)                                           
    

    Of course I can do it the es5 way -

    const a = b[b.length - 1]
    

    But maybe this is a bit prone to off by one errors. Can the splat only be the last thing in the destructuring?

  • caub
    caub almost 8 years
    uhh, it's quite bad, even .slice(-1)[0] is slighly less bad, or var [last]=arr.slice().reverse() is another ugly one if you need
  • shoesel
    shoesel almost 8 years
    I thought this post was about ES6/ES2015, no? But I like especially your last piece. How about combining the two: var [last] = arr.slice(-1) ;)
  • caub
    caub almost 8 years
    my favorite way is Object.defineProperty(Array.prototype, -1, { get() {return this[this.length - 1] } }); [1,2,3][-1]
  • shoesel
    shoesel over 7 years
    I love javascript :)
  • Vadorequest
    Vadorequest over 7 years
    Smart. Better than const last = ['bbb', 'uuu', 'iii'].slice(-1); ? In terms of performances?
  • shaunc
    shaunc over 7 years
    a = [1, 2, 3, 4, 5]; eval(`[${('' + a).replace(/[^,]/g, '')}x] = a`); x yields 5 :)
  • shoesel
    shoesel almost 7 years
    @shaunc: This only works for simple types, try adding an object to the array.
  • Jack Steam
    Jack Steam almost 7 years
    Nice simple non-mutative solution.
  • Bergi
    Bergi over 6 years
    I don't see any elegance in this solution, but anyway @shoesel already posted it
  • GavKilbride
    GavKilbride over 6 years
    Although this works it's mutative and removes the item from the original array. Not ideal in many scenarios.
  • Dave Newton
    Dave Newton almost 6 years
    @Shanimal Depends, I'm getting the pop version as faster (OS X, Chrome 68).
  • Dan
    Dan almost 6 years
    @GavKilbride it doesn't. Example is the same as [].concat(arr).pop(); which doesn't mutate arr.
  • Antonio Pantano
    Antonio Pantano almost 6 years
    @Dave Newton But pop() cause mutation
  • Dave Newton
    Dave Newton almost 6 years
    @AntonioPantano Yes, it mutates the copy. Point was whether or not it's faster isn't a given.
  • mix3d
    mix3d over 5 years
    the .slice(-1) is technically faster, but it does not give you both the last item AND the subarray in one call, which is a benefit of the ... splat when destructuring. Performance hit of reversing twice is to be considered when used on longer arrays, but for a small script probably worth the convenience? But you could just as easily let a = array.slice(-1), rest = array.slice(0,array.length-2) if you still wanted the oneliner in ES5, that is ~4% faster. jsperf.com/last-array-splat
  • andrhamm
    andrhamm over 4 years
    Yes, I find it useful when already doing other destructuring. By itself it is not as easy to read as the classic solution.
  • Hashbrown
    Hashbrown over 4 years
    @caub for your first comment, instead of the reverse, I'd probably do let [last] = arr.slice(-1); instead of reverse if you're going to use slice and destructuring anyway
  • petitkriket
    petitkriket over 3 years
    should be the selected solution
  • oriadam
    oriadam over 3 years
    to return the value 'program' and not ['program'] use ['a','b','program'].slice(-1)[0]. for empty array this will return undefined
  • Константин Ван
    Константин Ван about 3 years
    You don’t have to catch the length. ...rest would be more useful.
  • Shane Hsu
    Shane Hsu about 3 years
    I must add that JavaScript Array reverse is done in-place. So this solution might not suit every person, and/or have performance issues. I've been burned...
  • Den Kerny
    Den Kerny about 3 years
    @КонстантинВан true, it's common, mine is rare, but trully useful
  • ncubica
    ncubica about 2 years
    this is quite clever :D
  • Mg Gm
    Mg Gm about 2 years
    This solution still mutates the original array , which is not ideal in real life scenarios.
  • VLAZ
    VLAZ about 2 years
    Basically the same as this solution. It still has the same problem of mutating the array.
  • VLAZ
    VLAZ about 2 years
    There is no advantage at all to use reverse(). It takes unnecessary time and it mutates the array which is most likely also unnecessary. With mutation .pop() should be the idiomatic way to get the last item. Without mutation it's arr[arr.length - 1]