Por que o JavaScript não tem um último método? [fechadas]

124

É meio estranho que a classe JavaScript Array não ofereça um último método para recuperar o último elemento de uma matriz. Eu sei que a solução é simples (Ar [Ar.length-1]), mas, ainda assim, isso é usado com muita frequência.

Algum motivo sério para isso ainda não estar incorporado?

Nikhil Garg
fonte
39
Nos casos em que você não se importa de alterar a matriz como um efeito colateral (ou seja, onde a matriz é apenas temporária de qualquer maneira), o idioma seria item= array.pop();.
22910
7
Aqui está uma referência de desempenho para muitos dos métodos mencionados: jsperf.com/get-last-item-from-array
Web_Designer
5
Meu Deus, depois de olhar para essa página de perf, parece que array[array.length-1]é muito mais rápido que os outros.
Jondlm
@JondIm mas se você criar uma matriz em função, é necessário inventar nome local para ele (o que leva a nomes como ARR2), e você tem 2 linhas de código em vez de oneliner
Danubian marinheiro
1
(Ar[Ar.length-1])obtém um desempenho 20x melhor para mim.
Evgeni Sergeev

Respostas:

38

Porque o Javascript muda muito lentamente. E isso ocorre porque as pessoas atualizam os navegadores lentamente.

Muitas bibliotecas Javascript implementam suas próprias last()funções. Use um!

Tríptico
fonte
20
No mínimo, convém sugerir uma biblioteca que forneça a implementação. Por exemplo, Underscore.js é uma boa escolha. Veja documentcloud.github.com/underscore/#last
Sean Lynch
11
@ Sea - Eu pensei em ficar fora do negócio de recomendar uma biblioteca Javascript específica para o pôster original. O Google faz um bom trabalho ao avaliar a opinião coletiva da web sobre qual biblioteca usar. Por que eu sugeriria um em particular? De fato, por que você recomendou o underscore.js, que me parece muito sabor do mês à primeira vista?
Triptych
6
Na verdade, prefiro a resposta abaixo de implementar a função fora de uma biblioteca. Dito isto, como alguém que se deparou com essa pergunta pelo Google, eu estava sugerindo que a resposta principal ajudasse outras pessoas a continuar sua busca por uma solução, em vez de enviá-las para o botão Voltar.
Sean Lynch
5
A pergunta era "Por que esse recurso não está embutido no Javascript" e não "Como obter essa funcionalidade". Não há razão para pensar que o autor original estava procurando como realmente escrever sua própria last()função. A questão era sobre a natureza do desenvolvimento da própria linguagem principal do Javascript.
Triptych
3
Mas se o @Nikhil quiser saber como implementá-lo - o sublinhado tem uma fonte anotada maravilhosa. Essa implementação de last () é bastante robusta, provavelmente mais do que isso é necessária para este autor, mas é ótima para uma biblioteca. documentcloud.github.com/underscore/docs/…
reconbot
264

Você pode fazer algo assim:

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

A quantidade de métodos auxiliares que podem ser adicionados a um idioma é infinita. Suponho que eles simplesmente não consideraram adicionar este.

Álvaro González
fonte
11
tentados a downvote para "perto de infinito"
Tríptico
11
Por quê? Você pode chegar tão perto quanto você quiser, sem limite :)
Álvaro González
35
Este deve ser a resposta.
Giampaolo Rodolà
7
@UpTheCreek, porque você não precisa armazenar a matriz em uma variável.
Rmobis
5
@ ÁlvaroG.Vicario Isso é bom para uma série de referências, mas no seu exemplo você está trabalhando com números. Conforme o documento MDN: "fatia copia seqüências de caracteres e números para a nova matriz. Alterações na sequência ou número de uma matriz não afetam a outra matriz". Se o desenvolvedor quiser obter uma referência "array.last" para fazer algo com o valor do último elemento em sua matriz original, e os valores da matriz forem literais de sequência ou número, esse método não funcionará.
1nfiniti
82

É fácil definir um você mesmo. Esse é o poder do JavaScript.

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

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

No entanto, isso pode causar problemas com o código de terceiros que (incorretamente) usa for..in loops para iterar sobre matrizes.

No entanto, se você não estiver vinculado a problemas de suporte ao navegador , o uso da nova sintaxe ES5 para definir propriedades pode resolver esse problema, tornando a função não enumerável, da seguinte forma:

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
fonte
11
Observe que a adição de propriedades ao protótipo da matriz pode quebrar o código onde for..in é usado para iterar sobre uma matriz. Usar for..in para iterar uma matriz é uma prática ruim, mas isso é feito com a frequência necessária para alterar o protótipo do Array também. Em geral, os protótipos de Objeto, Matriz, String, Número, Booleano e Data não devem ser alterados se o seu script precisar trabalhar com outro código desconhecido.
Dagg Nabbit
7
@ não - Obrigado pela dica. Eu deveria ter mencionado que o motivo para adicionar a sintaxe ES5 com a enumerabilidade definida como false foi precisamente para resolver o for..inproblema. Claro, ainda não estamos lá com uma ampla implementação do ES5, mas é bom saber agora, já que os navegadores estão alcançando rapidamente, incluindo o IE9.
Anurag
4
Para listas vazias, this.length - 1avalia como -1, que, por ser um número negativo, é tratado como uma propriedade da matriz, não como um índice de elemento.
Clay Clay #
26

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

ícone gato adora pipoca

Silviu-Marian
fonte
15
Aviso: isso cria uma cópia da lista inteira apenas para exibir um elemento. Potencialmente muito desperdício de tempo e espaço. Não faça isso.
Triptych
13

Outra opção, especialmente se você já estiver usando o UnderscoreJS, seria:

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

x = [1,2];
alert( x.last() )
meder omuraliev
fonte
Qual deve ser a saída apropriada para [] .last ()? nullou undefined?
Álvaro González
1
provavelmente indefinido para mantê-lo consistente em termos de idioma.
Meder omuraliev
null Eu acho - porque você tem uma matriz bem definida - apenas que não há objetos válidos nela. undefined deve ser usado apenas quando a última 'propriedade' não estiver definida no contêiner chamado.
Nikhil Garg
3
apenas retornar this[l-1]forneceria undefinednormalmente o acesso a propriedades inexistentes. Pessoalmente, prefiro que JS jogue uma exceção em vez de retornar undefined, mas JS prefere varrer os erros para debaixo do tapete.
22910
4

Vim aqui procurando uma resposta para esta pergunta eu mesmo. A resposta da fatia é provavelmente a melhor, mas fui em frente e criei uma "última" função apenas para praticar a extensão de protótipos, então pensei em ir em frente e compartilhá-la. Ele tem o benefício adicional sobre alguns outros de permitir que você conte opcionalmente de trás para frente através da matriz e retire, digamos, o segundo para o último ou o terceiro para o último item. Se você não especificar uma contagem, o padrão será 1 e o último item será retirado.

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
fonte
Quando você usa last(4)ou last(9)perde o significado do nome da função, ou seja; last
Prashanth Shyamprasad
3

Aqui está outra maneira mais simples de dividir os últimos elementos

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

lastObj é agora ["barfoo"] .

O Python faz isso da mesma maneira e, quando tentei usar o JS, funcionou. Suponho que a manipulação de strings nas linguagens de script funcione da mesma maneira.

Da mesma forma, se você deseja os dois últimos objetos em uma matriz,

var lastTwoObj = tags.slice(-2)

vai te dar ["foobar", "barfoo"]e assim por diante.

Prashant
fonte
@Jakub Obrigado pela edição. Perdi o sinal negativo crucial.
Prashant
Não, lastObjconterá ["barfoo"]. De qualquer forma, por que eu faria em Array.prototype.slice.call(tagsvez de apenas tags.slice?
2

pop()O método exibirá o último valor. Mas o problema é que você perderá o último valor na matriz

Prashanth Shyamprasad
fonte
-1

Sim, ou apenas:

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

se você deseja o valor, e não uma nova lista.

TDahl
fonte
10
Não tenho certeza, mas isso parece bastante lento
Jonathan Azulay
3
Além de lento, também tem um efeito colateral desagradável, pois a matriz original é invertida.
Stephen Quan