Чому у JavaScript немає останнього методу? [зачинено]


124

Своїм дивним виглядом є те, що клас Array JavaScript не пропонує останнього методу для отримання останнього елемента масиву. Я знаю, що рішення просте (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 рядки коду замість oneliner
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 хоче знати, як це реалізувати - підкреслення має чудове анотоване джерело. Ця реалізація останнього () є досить надійною, ймовірно, більше цього потрібно цьому автору, але чудово підходить для бібліотеки. documentcloud.github.com/underscore/docs/…
рекобат

264

Ви можете зробити щось подібне:

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

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


11
спокусився взяти участь у "наближенні до нескінченності"
Триптих

11
Чому? Ви можете підійти так близько, як захочете, без обмежень :)
Álvaro González

35
Це має бути відповіддю.
Giampaolo Rodolà

7
@UpTheCreek, тому що вам не потрібно зберігати масив до змінної.
rmobis

5
@ ÁlvaroG.Vicario Це добре для масиву посилань, але у вашому прикладі ви працюєте з числами. Відповідно до документа MDN: "фрагмент копіює рядки та числа в новий масив. Зміни рядка чи числа в одному масиві не впливають на інший масив." Якщо розробник хоче отримати посилання "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
зауважте, що додавання властивостей до прототипу Array може порушити код, де для..in використовується ітерація над масивом. Використання для..in для ітерації масиву є поганою практикою, але це робиться досить часто, що зміна прототипу Array також є поганою практикою. Загалом, прототипи Object, Array, String, Number, Boolean і Date не повинні змінюватися, якщо ваш сценарій повинен працювати з іншим невідомим кодом.
Dagg Nabbit

7
@no - Дякую за пораду. Я мав би зазначити, що причиною додавання синтаксису ES5 із перелічуванням, встановленим у false, було саме вирішення for..inпроблеми. Звичайно, у нас ще немає широкої реалізації ES5, але це досить добре, щоб зараз знати, як браузери швидко досягають цього, включаючи IE9.
Анураг

4
Для порожніх списків this.length - 1оцінюється до -1, яке, оскільки це від'ємне число, трактується як властивість масиву, а не як індекс елемента.
кламація

26

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

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


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?
Альваро Гонсалес

1
ймовірно, невизначено, щоб підтримувати його послідовно.
meder omuraliev

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
Прашант Шямпрасад

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"]і так далі.


@Jakub Дякую за редагування Я пропустив вирішальний негативний знак.
Прашант

Ні, lastObjміститиме ["barfoo"]. У будь-якому випадку, чому я б робив Array.prototype.slice.call(tagsзамість просто tags.slice?

2

pop()метод виведе останнє значення. Але проблема полягає в тому, що ви втратите останнє значення в масиві


-1

Так, або просто:

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

якщо ви хочете значення, а не новий список.


10
Не впевнений, але це здається досить повільним
Джонатан Азулай

3
Крім того, що він повільний, він також має неприємний побічний ефект у тому, що початковий масив є зворотним.
Стівен Куан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.