Почему в JavaScript нет последнего метода? [закрыто]

124

Довольно странно, что класс JavaScript Array не предлагает последний метод для получения последнего элемента массива. Я знаю, что решение простое (Ar [Ar.length-1]), но, тем не менее, оно используется слишком часто.

Есть ли серьезные причины, по которым это еще не включено?

Нихил Гарг
источник
39
Для случаев, когда вы не возражаете против изменения массива в качестве побочного эффекта (то есть, когда массив в любом случае является временным), идиома будет item= array.pop();.
bobince
7
Вот тест производительности для многих из упомянутых методов: jsperf.com/get-last-item-from-array
Web_Designer
5
Помилуйте, посмотрев на этой странице перфорации, она появляется array[array.length-1]в пути быстрее , чем другие.
Jondlm
@JondIm, но если вы создаете массив в функции, вам нужно придумать для него локальное имя (что приводит к таким именам, как arr2), и у вас есть 2 строки кода вместо одного лайнера
Danubian Sailor
1
(Ar[Ar.length-1])получает в 20 раз лучшую производительность для меня.
Евгений Сергеев

Ответы:

38

Потому что Javascript меняется очень медленно. И это потому, что люди медленно обновляют браузеры.

Многие библиотеки Javascript реализуют свои собственные last()функции. Используйте один!

Триптих
источник
20
По крайней мере, вы можете подумать о том, чтобы предложить библиотеку, которая обеспечила бы реализацию. Например, Underscore.js - хороший выбор. См. Documentcloud.github.com/underscore/#last
Шон Линч,
11
@Sean - Я подумал, что не буду рекомендовать конкретную библиотеку Javascript оригинальному плакату. Google неплохо оценивает коллективное мнение Интернета о том, какую библиотеку использовать. Почему я должен предложить именно тот? В самом деле, почему вы порекомендовали underscore.js, который на первый взгляд кажется мне очень вкусным?
Триптих
6
На самом деле я предпочитаю приведенный ниже ответ о реализации функции вне библиотеки. Тем не менее, как человек, который наткнулся на этот вопрос через Google, я предлагал, чтобы главный ответ помог другим продолжить поиск решения, а не отправлять их на кнопку возврата.
Шон Линч,
5
Вопрос был в том, «Почему эта функция не встроена в Javascript», а не в том, «Как реализовать эту функцию». Нет никаких оснований полагать, что первоначальный автор искал, как на самом деле написать свою собственную last()функцию. Вопрос касался характера развития самого базового языка Javascript.
Триптих
3
Но если @Nikhil хочет знать, как это реализовать - подчеркивание имеет замечательный аннотированный источник. Эта реализация last () довольно надежна, вероятно, этому автору нужно больше, но она отлично подходит для библиотеки. documentcloud.github.com/underscore/docs/…
Рекбота 01
264

Вы можете сделать что-то вроде этого:

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

Количество вспомогательных методов, которые можно добавить в язык, бесконечно. Я полагаю, они просто не подумали о добавлении этого.

Альваро Гонсалес
источник
11
соблазняется проголосовать против «близко к бесконечности»
Триптих
11
Зачем? Вы можете подойти так близко, как хотите, без ограничений :)
Альваро Гонсалес,
35
Это должен быть ответ.
Джампаоло Родола
7
@UpTheCreek, потому что вам не нужно сохранять массив в переменной.
rmobis
5
@ ÁlvaroG.Vicario Это нормально для массива ссылок, но в вашем примере вы работаете с числами. Согласно документу MDN: «slice копирует строки и числа в новый массив. Изменения строки или числа в одном массиве не влияют на другой массив». Если разработчик хочет получить ссылку «array.last», чтобы что-то сделать со значением последнего элемента в исходном массиве, а значения массива оказались строковыми или числовыми литералами, этот метод не будет работать.
1nfiniti
82

Один легко определить самостоятельно. В этом сила JavaScript.

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

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

Однако это может вызвать проблемы со сторонним кодом, который (неправильно) использует for..in циклы для перебора массивов.

Однако, если вы не связаны проблемами поддержки браузера , то использование нового синтаксиса ES5 для определения свойств может решить эту проблему, сделав функцию неперечисляемой, например:

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
Анураг
источник
11
обратите внимание, что добавление свойств к прототипу массива может нарушить код, в котором for..in используется для итерации по массиву. Использование for..in для итерации массива - плохая практика, но это делается достаточно часто, поэтому изменение прототипа Array также является плохой практикой. Как правило, прототипы Object, Array, String, Number, Boolean и Date не должны изменяться, если вашему скрипту необходимо работать с другим неизвестным кодом.
Dagg Nabbit
7
@no - Спасибо за подсказку. Я должен был упомянуть, что причина добавления синтаксиса ES5 с перечисляемостью, установленной на false, как раз и заключалась в решении for..inпроблемы. Конечно, мы еще не достигли широкой реализации ES5, но этого достаточно, чтобы знать, поскольку браузеры быстро его догоняют, включая IE9.
Anurag
4
Для пустых списков this.length - 1вычисляется значение -1, которое, поскольку это отрицательное число, рассматривается как свойство массива, а не как индекс элемента.
пластилин
26

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

значок кошка любит попкорн

Silviu-Marian
источник
15
Предупреждение: это создает копию всего списка только для того, чтобы выдвинуть один элемент. Потенциально очень расточительно как во времени, так и в пространстве. Не делай этого.
Триптих
13

Другой вариант, особенно если вы уже используете UnderscoreJS, будет:

_.last([1, 2, 3, 4]); // Will return 4
Пабло Диас
источник
5
Array.prototype.last = Array.prototype.last || function() {
    var l = this.length;
    return this[l-1];
}

x = [1,2];
alert( x.last() )
Медер Омуралиев
источник
Каким должен быть соответствующий вывод для [] .last ()? nullили undefined?
Álvaro González,
1
вероятно, undefined, чтобы сохранить единообразие языка.
медер омуралиев
null Я думаю, потому что у вас есть хорошо определенный массив, просто в нем нет действительных объектов. undefined следует использовать, только когда последнее «свойство» не определено в вызываемом контейнере.
Nikhil Garg
3
просто возвращение this[l-1]даст вам, undefinedкак обычно, доступ к несуществующим свойствам. Лично я бы предпочел, чтобы JS генерировал исключение, а не возвращался undefined, но JS предпочитает скрывать ошибки.
bobince
4

Я пришел сюда в поисках ответа на этот вопрос. Срезанный ответ, вероятно, лучший, но я пошел дальше и создал «последнюю» функцию, просто чтобы попрактиковаться в расширении прототипов, поэтому я подумал, что пойду вперед и поделюсь ею. Он имеет дополнительное преимущество по сравнению с некоторыми другими, так как позволяет вам необязательно считать в обратном порядке по массиву и вытаскивать, скажем, предпоследний или третий до последнего элемент. Если вы не укажете счетчик, по умолчанию он будет равен 1 и вытащит последний элемент.

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
Даниил
источник
Когда вы используете last(4)или last(9)теряете смысл имени функции, т.е. last
Prashanth Shyamprasad
3

Вот еще один более простой способ разрезать последние элементы

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

lastObjсейчас ["barfoo"].

Python делает это так же, и когда я попытался использовать JS, это сработало. Я предполагаю, что манипуляции со строками в языках сценариев работают одинаково.

Точно так же, если вам нужны последние два объекта в массиве,

var lastTwoObj = tags.slice(-2)

даст вам ["foobar", "barfoo"]и так далее.

Prashant
источник
@Jakub Спасибо за редактирование. Я упустил решающий отрицательный знак.
Prashant
Нет, lastObjбудет содержать ["barfoo"]. В любом случае, зачем мне это делать, Array.prototype.slice.call(tagsа не просто tags.slice?
2

pop()метод выведет последнее значение. Но проблема в том, что вы потеряете последнее значение в массиве

Прашант Шьямпрасад
источник
-1

Да, или просто:

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

если вам нужно значение, а не новый список.

TDahl
источник
10
Не уверен, но это кажется довольно медленным
Джонатан Азулай
3
Помимо того, что он медленный, он также имеет неприятный побочный эффект в том, что исходный массив перевернут.
Стивен Куан