Dlaczego JavaScript nie ma ostatniej metody? [Zamknięte]

124

To trochę dziwne, że klasa JavaScript Array nie oferuje ostatniej metody pobierania ostatniego elementu tablicy. Wiem, że rozwiązanie jest proste (Ar [Ar.length-1]), ale nadal jest to zbyt często używane.

Jakieś poważne powody, dla których nie jest to jeszcze włączone?

Nikhil Garg
źródło
39
W przypadkach, w których nie masz nic przeciwko zmianie tablicy jako efektu ubocznego (tj. Gdzie tablica i tak jest tylko tymczasowa), idiom będzie item= array.pop();.
bobince
7
Oto test wydajności dla wielu z wymienionych metod: jsperf.com/get-last-item-from-array
Web_Designer
5
Dobry Boże, po obejrzeniu strony z perfekcją okazuje się, że array[array.length-1]jest znacznie szybsza niż inne.
Jondlm
@JondIm, ale jeśli utworzysz tablicę w funkcji, musisz wymyślić dla niej lokalną nazwę (która prowadzi do nazw takich jak arr2), a masz 2 linie kodu zamiast onelinera
Danubian Sailor
1
(Ar[Ar.length-1])osiąga dla mnie 20x lepszą wydajność.
Evgeni Sergeev

Odpowiedzi:

38

Ponieważ JavaScript zmienia się bardzo powoli. A to dlatego, że ludzie powoli aktualizują przeglądarki.

Wiele bibliotek JavaScript implementuje własne last()funkcje. Użyj jednego!

Tryptyk
źródło
20
Przynajmniej możesz rozważyć zasugerowanie biblioteki, która zapewniłaby implementację. Na przykład Underscore.js to dobry wybór. Zobacz documentcloud.github.com/underscore/#last
Sean Lynch,
11
@Sean - Pomyślałem, że nie będę się zajmować polecaniem konkretnej biblioteki JavaScript do oryginalnego plakatu. Google całkiem nieźle radzi sobie z oceną zbiorowej opinii sieci na temat biblioteki, której należy użyć. Dlaczego miałbym zaproponować konkretny? Rzeczywiście, dlaczego poleciłeś podkreślenie underscore.js, które na pierwszy rzut oka wydaje mi się bardzo smaczne?
Tryptyk
6
Właściwie wolę odpowiedź poniżej dotyczącą implementacji funkcji poza biblioteką. To powiedziawszy, jako ktoś, kto natknął się na to pytanie za pośrednictwem Google, sugerowałem, aby najlepsza odpowiedź pomogła innym w kontynuowaniu poszukiwania rozwiązania, zamiast wysyłać ich do przycisku Wstecz.
Sean Lynch
5
Pytanie brzmiało „Dlaczego ta funkcja nie jest wbudowana w Javascript”, a nie „Jak można osiągnąć tę funkcjonalność”. Nie ma powodu, by sądzić, że oryginalny autor szukał, jak właściwie napisać własną last()funkcję. Pytanie dotyczyło natury samego rozwoju podstawowego języka Javascript.
Tryptyk
3
Ale jeśli @Nikhil chce wiedzieć, jak to zaimplementować - podkreślenie ma wspaniałe źródło z adnotacjami. Ta implementacja last () jest dość solidna, prawdopodobnie więcej jest potrzebna temu autorowi, ale świetnie nadaje się do biblioteki. documentcloud.github.com/underscore/docs/…
recbot
264

Możesz zrobić coś takiego:

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

Ilość metod pomocniczych, które można dodać do języka, jest nieskończona. Przypuszczam, że po prostu nie rozważali dodania tego.

Álvaro González
źródło
11
kuszony, by głosować w dół za „blisko nieskończoności”
Tryptyk
11
Czemu? Możesz podejść tak blisko, jak chcesz, bez limitu :)
Álvaro González
35
Ta powinna być odpowiedzią.
Giampaolo Rodolà
7
@UpTheCreek, ponieważ nie musisz przechowywać tablicy w zmiennej.
rmobis
5
@ ÁlvaroG.Vicario To jest dobre dla tablicy odniesień, ale w twoim przykładzie pracujesz z liczbami. Zgodnie z dokumentem MDN: „plaster kopiuje ciągi i liczby do nowej tablicy. Zmiany w ciągu lub liczbie w jednej tablicy nie mają wpływu na drugą tablicę”. Jeśli programista chce uzyskać odniesienie „array.last”, aby zrobić coś z wartością ostatniego elementu w swojej oryginalnej tablicy, a wartości tablicy są literałami łańcuchowymi lub liczbowymi, ta metoda nie zadziała.
1nfiniti
82

Łatwo jest samemu go zdefiniować. To jest siła JavaScript.

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

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

Może to jednak powodować problemy z kodem innej firmy, który (nieprawidłowo) używa for..in pętli do iteracji po tablicach.

Jeśli jednak nie jesteś związany z problemami z obsługą przeglądarek , użycie nowej składni ES5 do definiowania właściwości może rozwiązać ten problem, sprawiając, że funkcja nie jest wyliczalna, na przykład:

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
Anurag
źródło
11
zwróć uwagę, że dodanie właściwości do prototypu Arraya może spowodować uszkodzenie kodu, w którym for..in jest używane do iteracji po tablicy. Używanie for..in do iteracji tablicy jest złą praktyką, ale robi się to na tyle często, że zmiana prototypu Arraya jest również złą praktyką. Ogólnie rzecz biorąc, prototypy Object, Array, String, Number, Boolean i Date nie powinny być zmieniane, jeśli skrypt musi współpracować z innym nieznanym kodem.
Dagg Nabbit
7
@no - Dzięki za wskazówkę. Powinienem był wspomnieć, że powodem dodania składni ES5 z wyliczalnością ustawioną na false było właśnie rozwiązanie for..inproblemu. Jasne, nie jesteśmy jeszcze tam z szeroką implementacją ES5, ale wystarczy wiedzieć teraz, ponieważ przeglądarki szybko to dogrywają, w tym IE9.
Anurag,
4
W przypadku pustych list zwraca this.length - 1wartość -1, która, ponieważ jest liczbą ujemną, jest traktowana jako właściwość tablicy, a nie indeks elementu.
claymation
26

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

ikona kota uwielbia popcorn

Silviu-Marian
źródło
15
Ostrzeżenie: tworzy to kopię całej listy tylko po to, aby wstawić jeden element. Potencjalnie bardzo marnotrawne zarówno w czasie, jak i przestrzeni. Nie rób tego.
Tryptyk
13

Inną opcją, zwłaszcza jeśli używasz już UnderscoreJS, byłoby:

_.last([1, 2, 3, 4]); // Will return 4
Pablo Diaz
źródło
5
Array.prototype.last = Array.prototype.last || function() {
    var l = this.length;
    return this[l-1];
}

x = [1,2];
alert( x.last() )
meder omuraliev
źródło
Jaki powinien być odpowiedni wynik dla [] .last ()? nullczy undefined?
Álvaro González
1
prawdopodobnie niezdefiniowane, aby zachować spójność językową.
meder omuraliev
null Myślę - ponieważ masz dobrze zdefiniowaną tablicę - tylko że nie ma w niej ważnych obiektów. undefined powinno być używane tylko wtedy, gdy ostatnia właściwość nie jest zdefiniowana w wywołanym kontenerze.
Nikhil Garg,
3
samo zwrócenie this[l-1]dałoby ci undefinednormalny dostęp do nieistniejących właściwości. Osobiście wolałbym, żeby JS rzucił wyjątek, zamiast wracać undefined, ale JS woli zamiatać błędy pod dywan.
bobince
4

Przyszedłem tutaj, szukając odpowiedzi na to pytanie. Odpowiedź na wycinek jest prawdopodobnie najlepsza, ale zdecydowałem się na „ostatnią” funkcję tylko po to, aby poćwiczyć rozszerzanie prototypów, więc pomyślałem, że będę mógł się nią podzielić. Ma dodatkową zaletę w stosunku do niektórych innych, ponieważ umożliwia opcjonalne liczenie wstecz w tablicy i wyciąganie, powiedzmy, elementu przedostatniego lub trzeciego do ostatniego. Jeśli nie określisz liczby, po prostu domyślnie 1 i wyciągnie ostatni element.

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
źródło
Kiedy używasz last(4)lub last(9)tracisz znaczenie nazwy funkcji, tj; last
Prashanth Shyamprasad
3

Oto kolejny prostszy sposób na pokrojenie ostatnich elementów

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

lastObj jest teraz ["barfoo"] .

Python robi to w ten sam sposób, a kiedy próbowałem użyć JS, wyszło. Domyślam się, że manipulacja napisami w językach skryptowych działa w ten sam sposób.

Podobnie, jeśli chcesz, aby ostatnie dwa obiekty w tablicy,

var lastTwoObj = tags.slice(-2)

da ci ["foobar", "barfoo"]i tak dalej.

Prashant
źródło
@Jakub Dziękuję za edycję. Brakowało mi decydującego znaku ujemnego.
Prashant
Nie, lastObjbędzie zawierać ["barfoo"]. W każdym razie, dlaczego miałbym to zrobić Array.prototype.slice.call(tagszamiast tylko tags.slice?
2

pop()metoda wyrzuci ostatnią wartość. Problem polega jednak na tym, że utracisz ostatnią wartość w tablicy

Prashanth Shyamprasad
źródło
-1

Tak, lub po prostu:

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

jeśli chcesz mieć wartość, a nie nową listę.

TDahl
źródło
10
Nie jestem pewien, ale wydaje się to dość powolne
Jonathan Azulay
3
Oprócz tego, że jest powolny, ma również nieprzyjemny efekt uboczny polegający na odwróceniu oryginalnej tablicy.
Stephen Quan