1470
votes

Here is my JavaScript code so far:

var linkElement = document.getElementById("BackButton");
var loc_array = document.location.href.split('/');
var newT = document.createTextNode(unescape(capWords(loc_array[loc_array.length-2]))); 
linkElement.appendChild(newT);

Currently it takes the second to last item in the array from the URL. However, I want to do a check for the last item in the array to be "index.html" and if so, grab the third to last item instead.

30

30 Answers

1509
votes
if (loc_array[loc_array.length - 1] === 'index.html') {
   // do something
} else {
   // something else
}

In the event that your server serves the same file for "index.html" and "inDEX.htML" you can also use: .toLowerCase().

Though, you might want to consider doing this server-side if possible: it will be cleaner and work for people without JS.

1348
votes

Not sure if there's a drawback, but this seems quite concise:

arr.slice(-1)[0] 

or

arr.slice(-1).pop()

Both will return undefined if the array is empty.

339
votes

Use Array.pop:

var lastItem = anArray.pop();

Important : This returns the last element and removes it from the array

187
votes

A shorter version of what @chaiguy posted:

Array.prototype.last = function() {
    return this[this.length - 1];
}

Reading the -1 index returns undefined already.

EDIT:

These days the preference seems to be using modules and to avoid touching the prototype or using a global namespace.

export function last(array) {
    return array[array.length - 1];
}
170
votes

Two options are:

var last = arr[arr.length - 1]

or

var last = arr.slice(-1)[0]

The former is faster, but the latter looks nicer

http://jsperf.com/slice-vs-length-1-arr

83
votes

Here's how to get it with no effect on the original ARRAY

a = [1,2,5,6,1,874,98,"abc"];
a.length; //returns 8 elements

If you use pop(), it will modify your array

a.pop();  // will return "abc" AND REMOVES IT from the array 
a.length; // returns 7

But you can use this so it has no effect on the original array:

a.slice(-1).pop(); // will return "abc" won't do modify the array 
                   // because slice creates a new array object 
a.length;          // returns 8; no modification and you've got you last element 
79
votes

Performance

Today 2020.05.16 I perform tests of chosen solutions on Chrome v81.0, Safari v13.1 and Firefox v76.0 on MacOs High Sierra v10.13.6

Conclusions

  • arr[arr.length-1] (D) is recommended as fastest cross-browser solution
  • mutable solution arr.pop() (A) and immutable _.last(arr) (L) are fast
  • solutions I, J are slow for long strings
  • solutions H, K (jQuery) are slowest on all browsers

enter image description here

Details

I test two cases for solutions:

  • mutable: A, B, C,

  • immutable: D, E, F, G, H, I, J (my),

  • immutable from external libraries: K, L, M,

for two cases

  • short string - 10 characters - you can run test HERE
  • long string - 1M characters - you can run test HERE

function A(arr) {
  return arr.pop();
}

function B(arr) {  
  return arr.splice(-1,1);
}

function C(arr) {  
  return arr.reverse()[0]
}

function D(arr) {
  return arr[arr.length - 1];
}

function E(arr) {
  return arr.slice(-1)[0] ;
}

function F(arr) {
  let [last] = arr.slice(-1);
  return last;
}

function G(arr) {
  return arr.slice(-1).pop();
}

function H(arr) {
  return [...arr].pop();
}

function I(arr) {  
  return arr.reduceRight(a => a);
}

function J(arr) {  
  return arr.find((e,i,a)=> a.length==i+1);
}

function K(arr) {  
  return $(arr).get(-1);
}

function L(arr) {  
  return _.last(arr);
}

function M(arr) {  
  return _.nth(arr, -1);
}






// ----------
// TEST
// ----------

let loc_array=["domain","a","b","c","d","e","f","g","h","file"];

log = (f)=> console.log(`${f.name}: ${f([...loc_array])}`);

[A,B,C,D,E,F,G,H,I,J,K,L,M].forEach(f=> log(f));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js" integrity="sha256-VeNaFBVDhoX3H+gJ37DpT/nTuZTdjYro9yBruHjVmoQ=" crossorigin="anonymous"></script>

Example results for Chrome for short string

enter image description here

61
votes

The "cleanest" ES6 way (IMO) would be:

const foo = [1,2,3,4];
const bar = [...foo].pop();

This avoids mutating foo, as .pop() would had, if we didn't used the spread operator.
That said, I like aswell the foo.slice(-1)[0] solution.

47
votes

const [lastItem] = array.slice(-1);

Array.prototype.slice with -1 can be used to create a new Array containing only the last item of the original Array, you can then use Destructuring Assignment to create a variable using the first item of that new Array.

const lotteryNumbers = [12, 16, 4, 33, 41, 22];
const [lastNumber] = lotteryNumbers.slice(-1);

console.log(lotteryNumbers.slice(-1));
// => [22]
console.log(lastNumber);
// => 22
45
votes

I'd rather use array.pop() than indexes.

while(loc_array.pop()!= "index.html"){
}
var newT = document.createTextNode(unescape(capWords(loc_array[loc_array.length])));

this way you always get the element previous to index.html (providing your array has isolated index.html as one item). Note: You'll lose the last elements from the array, though.

33
votes

You can use this pattern...

let [last] = arr.slice(-1);

While it reads rather nicely, keep in mind it creates a new array so it's less efficient than other solutions but it'll almost never be the performance bottleneck of your application.

32
votes
const lastElement = myArray[myArray.length - 1];

This is the best options from performance point of view (~1000 times faster than arr.slice(-1)).

30
votes

Getting the last item of an array can be achieved by using the slice method with negative values.

You can read more about it here at the bottom.

var fileName = loc_array.slice(-1)[0];
if(fileName.toLowerCase() == "index.html")
{
  //your code...
}

Using pop() will change your array, which is not always a good idea.

29
votes

If one wants to get the last element in one go, he/she may use Array#splice():

lastElement = document.location.href.split('/').splice(-1,1);

Here, there is no need to store the split elements in an array, and then get to the last element. If getting last element is the only objective, this should be used.

Note: This changes the original array by removing its last element. Think of splice(-1,1) as a pop() function that pops the last element.

27
votes

This question has been around a long time, so I'm surprised that no one mentioned just putting the last element back on after a pop().

arr.pop() is exactly as efficient as arr[arr.length-1], and both are the same speed as arr.push().

Therefore, you can get away with:

---EDITED [check that thePop isn't undefined before pushing]---

let thePop = arr.pop()
thePop && arr.push(thePop)

---END EDIT---

Which can be reduced to this (same speed [EDIT: but unsafe!]):

arr.push(thePop = arr.pop())    //Unsafe if arr empty

This is twice as slow as arr[arr.length-1], but you don't have to stuff around with an index. That's worth gold on any day.

Of the solutions I've tried, and in multiples of the Execution Time Unit (ETU) of arr[arr.length-1]:

[Method]..............[ETUs 5 elems]...[ETU 1 million elems]

arr[arr.length - 1]      ------> 1              -----> 1

let myPop = arr.pop()
arr.push(myPop)          ------> 2              -----> 2

arr.slice(-1).pop()      ------> 36             -----> 924  

arr.slice(-1)[0]         ------> 36             -----> 924  

[...arr].pop()           ------> 120            -----> ~21,000,000 :)

The last three options, ESPECIALLY [...arr].pop(), get VERY much worse as the size of the array increases. On a machine without the memory limitations of my machine, [...arr].pop() probably maintains something like it's 120:1 ratio. Still, no one likes a resource hog.

27
votes

Multiple ways to find last value of an array in javascript

  • Without affecting original array

var arr = [1,2,3,4,5];

console.log(arr.slice(-1)[0])
console.log(arr[arr.length-1])
const [last] = [...arr].reverse();
console.log(last)

let copyArr = [...arr];
console.log(copyArr.reverse()[0]);
  • Modifies original array

var arr = [1,2,3,4,5];

console.log(arr.pop())
arr.push(5)
console.log(...arr.splice(-1));
  • By creating own helper method

let arr = [1, 2, 3, 4, 5];

Object.defineProperty(arr, 'last', 
{ get: function(){
  return this[this.length-1];
 }
})

console.log(arr.last);
24
votes

Just putting another option here.

loc_array.splice(-1)[0] === 'index.html'

I found the above approach more clean and short onliner. Please, free feel to try this one.

Note: It will modify the original array, if you don't want to modify it you can use slice()

loc_array.slice(-1)[0] === 'index.html'

Thanks @VinayPai for pointing this out.

22
votes

ES6 object destructuring is another way to go.

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

You extract length property from Array using object destructuring. You create another dynamic key using already extracted key by [length-1] and assign it to last, all in one line.

22
votes

TL;DR

const [y] = x.slice(-1)

Explanation:
This funny looking syntax [y] = <array-or-an-object> is actually called Destructuring assignment & according to Mozilla docs

"The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables"

Read more about it here

21
votes

For those not afraid to overload the Array prototype (and with enumeration masking you shouldn't be):

Object.defineProperty( Array.prototype, "getLast", {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function() {
        return this[ this.length - 1 ];
    }
} );
20
votes

I generally use underscorejs, with it you can just do

if (_.last(loc_array) === 'index.html'){
  etc...
}

For me that is more semantic than loc_array.slice(-1)[0]

20
votes

Here's more Javascript art if you came here looking for it

In the spirit of another answer that used reduceRight(), but shorter:

[3, 2, 1, 5].reduceRight(a => a);

It relies on the fact that, in case you don't provide an initial value, the very last element is selected as the initial one (check the docs here). Since the callback just keeps returning the initial value, the last element will be the one being returned in the end.

Beware that this should be considered Javascript art and is by no means the way I would recommend doing it, mostly because it runs in O(n) time, but also because it hurts readability.

And now for the serious answer

The best way I see (considering you want it more concise than array[array.length - 1]) is this:

const last = a => a[a.length - 1];

Then just use the function:

last([3, 2, 1, 5])

The function is actually useful in case you're dealing with an anonymous array like [3, 2, 1, 5] used above, otherwise you'd have to instantiate it twice, which would be inefficient and ugly:

[3, 2, 1, 5][[3, 2, 1, 5].length - 1]

Ugh.

For instance, here's a situation where you have an anonymous array and you'd have to define a variable, but you can use last() instead:

last("1.2.3".split("."));
19
votes

jQuery solves this neatly:

> $([1,2,3]).get(-1)
3
> $([]).get(-1)
undefined
18
votes

The Array.prototype.at proposal (stage 3) adds a method for relative indexing (MDN):

const myArray = [1, 2, 3]

console.log(myArray.at(-1))
// => 3

Another TC39 proposal, the Array.prototype.lastItem proposal (stage 1), adds a getter that returns the last item in an array:

const myArray = [1, 2, 3]

console.log(myArray.lastItem)
// => 3

The .at proposal is currently only implemented in pre-release versions of Firefox and Safari.

.lastItem is not supported in any browser, and the proposal’s champion currently considers withdrawing the proposal.

14
votes

To prevent removing last item from origin array you could use

Array.from(myArray).pop()

Mostly supported of all browsers (ES6)

13
votes

In ECMAScript proposal Stage 1 there is a suggestion to add an array property that will return the last element: proposal-array-last.

Syntax:

arr.lastItem // get last item
arr.lastItem = 'value' // set last item

arr.lastIndex // get last index

You can use polyfill.

Proposal author: Keith Cirkel(chai autor)

12
votes

Whatever you do don't just use reverse() !!!

A few answers mention reverse but don't mention the fact that reverse modifies the original array, and doesn't (as in some other language or frameworks) return a copy.

var animals = ['dog', 'cat'];

animals.reverse()[0]
"cat"

animals.reverse()[0]
"dog"

animals.reverse()[1]
"dog"

animals.reverse()[1]
"cat"

This can be the worst type of code to debug!

11
votes

Personally I would upvote answer by kuporific / kritzikratzi. The array[array.length-1] method gets very ugly if you're working with nested arrays.

var array = [[1,2,3], [4,5,6], [7,8,9]]
​
array.slice(-1)[0]
​
//instead of 
​
array[array.length-1]
​
//Much easier to read with nested arrays
​
array.slice(-1)[0].slice(-1)[0]
​
//instead of
​
array[array.length-1][array[array.length-1].length-1]
10
votes

I think this should work fine.

var arr = [1, 2, 3];
var last_element = arr.reverse()[0];

Just reverse the array and get the first element.

Edit: As mentioned below, the original array will be reversed. To avoid that you can change the code to:

var arr = [1, 2, 3];
var last_element = arr.slice().reverse()[0];

This will create a copy of the original array.

9
votes

You can add a last() function to the Array prototype.

Array.prototype.last = function () {
    return this[this.length - 1];
};