125

Its kinda weird that the JavaScript Array class does not offer a last method to retrieve the last element of an array. I know the solution is simple (Ar[Ar.length-1] ), but, still, this is too frequently used.

Any serious reasons why this is not incorporated yet?

Coleman
  • 565
  • 7
  • 15
Nikhil Garg
  • 3,944
  • 9
  • 30
  • 37
  • 39
    For cases where you don't mind altering the array as a side-effect (ie. where the array is only temporary anyway), the idiom would be `item= array.pop();`. – bobince Jul 13 '10 at 08:08
  • 7
    Here's a performance benchmark for many of the mentioned methods: http://jsperf.com/get-last-item-from-array – Web_Designer May 23 '13 at 02:52
  • 5
    Good heavens, after looking at that perf page, it appears `array[array.length-1]` is **way** faster than the others. – Jondlm May 30 '13 at 14:59
  • @JondIm but if you create an array in function, you need to invent local name for it (which leads to names such as arr2), and you have 2 lines of code instead of oneliner – Danubian Sailor Jun 07 '13 at 13:04
  • 1
    `(Ar[Ar.length-1])` gets 20x better performance for me. – Evgeni Sergeev Jun 19 '13 at 14:03
  • Duplicate of http://stackoverflow.com/questions/3216013/get-the-last-item-in-an-array – Oriol Jul 01 '13 at 02:01
  • I don't know if that's because of the recent firefox update that should improve JS, but for me, everything else than `array[array.length - 1]` resulted in nearly 99% slower (the pop-solution even 100%^^ in absolute: pop: 3,036,947 ops/s, array[len-1]: 693,161,390 ops/s. – Julian Jul 12 '13 at 23:06

10 Answers10

265

You can do something like this:

[10, 20, 30, 40].slice(-1)[0]

console.log([10, 20, 30, 40].slice(-1)[0])

The amount of helper methods that can be added to a language is infinite. I suppose they just haven't considered adding this one.

Álvaro González
  • 142,137
  • 41
  • 261
  • 360
  • 11
    tempted to downvote for "close to infinity" – Kenan Banks Jul 13 '10 at 07:44
  • 11
    Why? You can get as close as you want, no limit :) – Álvaro González Jul 13 '10 at 07:49
  • 35
    This one should be the answer. – Giampaolo Rodolà Dec 16 '11 at 13:58
  • 7
    @UpTheCreek, because you don't need to store the array to a variable. – rmobis Nov 29 '12 at 19:11
  • @UpTheCreek Also, not having to reference the array twice is nice. Good solution. – Jonathan Apr 11 '13 at 21:58
  • 5
    @ÁlvaroG.Vicario This is fine for an array of references, but in your example you're working with numbers. As per the MDN doc: "slice copies strings and numbers into the new array. Changes to the string or number in one array does not affect the other array." If the developer wants to get a reference "array.last" in order to do something with the value of the last element in their original array, and the array values happen to be string or number literals, this method will not work. – 1nfiniti May 21 '13 at 15:10
  • @GiampaoloRodolà I upvoted this for sure, but it is not the answer to the OP's question: "Any serious reasons why this is not incorporated yet?" – Ziggy Jul 17 '13 at 20:14
  • @ÁlvaroG.Vicario No matter now big a number gets, it is never any closer to infinity. The distance between any number and infinity is always infinity. Infinity has no position on the number line, therefore the phrase "close to infinity" (or "nearly infinite") is totally meaningless. – Michael Dorst Jul 30 '13 at 00:18
  • @anthropomorphic - Alright, I've just removed the goddamned word "near", I'm getting tired of this. It seems that my mother tongue is not as strict as English when using mathematical terms. – Álvaro González Jul 30 '13 at 06:03
  • @ÁlvaroG.Vicario I didn't intend to irritate you, I was just sharing what I consider to be a mathematical "fun fact" =) – Michael Dorst Jul 30 '13 at 06:40
  • @anthropomorphic - Please don't take it personally. It's only the issue has been polemic for three years now :) – Álvaro González Jul 30 '13 at 06:52
83

It's easy to define one yourself. That's the power of JavaScript.

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

var arr = [1, 2, 5];
arr.last(); // 5

However, this may cause problems with 3rd-party code which (incorrectly) uses for..in loops to iterate over arrays.

However, if you are not bound with browser support problems, then using the new ES5 syntax to define properties can solve that issue, by making the function non-enumerable, like so:

Object.defineProperty(Array.prototype, 'last', {
    enumerable: false,
    configurable: true,
    get: function() {
        return this[this.length - 1];
    },
    set: undefined
});

var arr = [1, 2, 5];
arr.last; // 5
jpaugh
  • 6,634
  • 4
  • 38
  • 90
Anurag
  • 140,337
  • 36
  • 221
  • 257
  • 11
    note that adding properties to Array's prototype can break code where for..in is used to iterate over an array. Using for..in to iterate an array is bad practice, but it's done commonly enough that altering Array's prototype is also bad practice. In general, prototypes of Object, Array, String, Number, Boolean, and Date should not be altered if your script needs to work with other unknown code. – Dagg Nabbit Jul 13 '10 at 08:35
  • 7
    @no - Thanks for the tip. I should've mentioned that the reason for adding the ES5 syntax with enumerability set to false was precisely to solve the `for..in` problem. Sure, we're not there yet with a wide implementation of ES5, but it's good enough to know now as browsers are catching up to it fast, including IE9. – Anurag Jul 13 '10 at 08:49
  • 4
    For empty lists, `this.length - 1` evaluates to `-1`, which, because it is a negative number, is treated as an array property, not an element index. – claymation Aug 06 '12 at 20:23
38

Because Javascript changes very slowly. And that's because people upgrade browsers slowly.

Many Javascript libraries implement their own last() function. Use one!

Kenan Banks
  • 207,056
  • 34
  • 155
  • 173
  • 21
    At the very least, you may want to consider suggesting a library that would provide the implementation. For example, Underscore.js is a good choice. See http://documentcloud.github.com/underscore/#last – Sean Lynch Oct 03 '11 at 22:37
  • 11
    @Sean - I thought I'd stay out of the business of recommending a particular Javascript library to the original poster. Google does a pretty good job of assessing the web's collective opinion on which library to use. Why would I suggest a particular one? Indeed, why have you recommended underscore.js, which seems very flavor-of-the-month to me at first glance? – Kenan Banks Oct 03 '11 at 23:18
  • 7
    I actually prefer the answer below of implementing the function outside of a library. That said, as someone that stumbled upon this question via Google, I was suggesting that the top answer help others continue their search for a solution rather than sending them to the back button. – Sean Lynch Oct 04 '11 at 18:38
  • 5
    The question was "Why isn't this feature built into Javascript" not "How can achieve this functionality". There is no reason to think the original author was looking for how to actually write his own `last()` function. The question was about the nature of the development of the Javascript core language itself. – Kenan Banks Oct 04 '11 at 18:53
  • 3
    But if @Nikhil wants to know how to implement it - underscore has a wonderful annotated source. This implementation of last() is quite robust, probably more then is needed by this author but great for a library. http://documentcloud.github.com/underscore/docs/underscore.html#section-36 – reconbot Jun 01 '12 at 14:35
  • Thanks @SeanLynch for underscore.js. I have been implementing many functions by myself so far. – Pujan Mar 27 '14 at 04:28
26

i = [].concat(loves).pop(); //corn

icon cat loves popcorn

Silviu-Marian
  • 10,565
  • 6
  • 50
  • 72
  • 16
    Warning: this creates a copy of the entire list just to pop one element. Potentially very wasteful in both time and space. Don't do it. – Kenan Banks Aug 16 '13 at 17:35
13

Another option, especially if you're already using UnderscoreJS, would be:

_.last([1, 2, 3, 4]); // Will return 4
Pablo D.
  • 620
  • 6
  • 15
5
Array.prototype.last = Array.prototype.last || function() {
    var l = this.length;
    return this[l-1];
}

x = [1,2];
alert( x.last() )
meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
  • What should be appropriate output for [].last()? `null` or `undefined`? – Álvaro González Jul 13 '10 at 07:48
  • 1
    probably undefined to keep it consistent language-wise. – meder omuraliev Jul 13 '10 at 07:51
  • null I think- because you do have an array well defined- just that there are no valid objects in it. undefined should be used only when last 'property' is not defined on the called container. – Nikhil Garg Jul 13 '10 at 07:52
  • 3
    just returning `this[l-1]` would give you `undefined` as is normal for accessing non-existent properties. Personally I'd rather JS threw an exception rather than returning `undefined`, but JS prefers to sweep errors under the rug. – bobince Jul 13 '10 at 08:04
4

Came here looking for an answer to this question myself. The slice answer is probably best, but I went ahead and created a "last" function just to practice extending prototypes, so I thought I would go ahead and share it. It has the added benefit over some other ones of letting you optionally count backwards through the array, and pull out, say, the second to last or third to last item. If you don't specify a count it just defaults to 1 and pulls out the last item.

Array.prototype.last = Array.prototype.last || function(count) {
    count = count || 1;
    var length = this.length;
    if (count <= length) {
        return this[length - count];
    } else {
        return null;
    }
};

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.last(); // returns 9
arr.last(4); // returns 6
arr.last(9); // returns 1
arr.last(10); // returns null
Daniel
  • 61
  • 3
3

Here is another simpler way to slice last elements

 var tags = [1, 2, 3, "foo", "bar", "foobar", "barfoo"];
 var lastObj = tags.slice(-1);

lastObj is now ["barfoo"].

Python does this the same way and when I tried using JS it worked out. I am guessing string manipulation in scripting languages work the same way.

Similarly, if you want the last two objects in a array,

var lastTwoObj = tags.slice(-2)

will give you ["foobar", "barfoo"] and so on.

Prashant
  • 1,825
  • 1
  • 15
  • 18
  • @Jakub Thank you for the edit. I missed the crucial negative sign. – Prashant Aug 16 '12 at 21:36
  • No, `lastObj` will contain `["barfoo"]`. In any case, why would I do `Array.prototype.slice.call(tags` instead of just `tags.slice`? –  Dec 29 '12 at 07:12
2

pop() method will pop the last value out. But the problem is that you will lose the last value in the array

Prashanth Shyamprasad
  • 827
  • 2
  • 17
  • 39
-1

Yeah, or just:

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

if you want the value, and not a new list.

yckart
  • 32,460
  • 9
  • 122
  • 129
TDahl
  • 23
  • 1