Last in list. Hacks and tricks with Array in JS


Сегодня пара слов про работу с массивами в JS. В целом работа с массивами (aka списками) в JavaScript — это большая тема. Что-то уже я когда-то описывал. Все в одну большую статью пихать не хочется — я сам не люблю лонгриды. Данный пост навеян недавним собеседованием.

Как получить значение последнего элемента массива?

Начал сам придумывать варианты решения и как-то увлекся, в итоге нагенерил кучу способов. Зачем? Зачем трюкач, владеющий мечами, крутит ими виртуозно, так что завораживает взгляд? Вот это примерно про тоже. Помимо спортивного интереса умение быстро придумать разные варианты означает что вы владеете своим инструментом и понимаете какие методы есть, что они делают и какой будет результат.

Умение показать нестандартный вариант — это про креатив, про то, что вы можете думать шире рамок и ограничений. В работе вы не будете так писать — да. Но тут речь не только о работе.

Think outside the box!

Получить последний элемент

Как получить доступ к первому знают все. А как взять последний элемент?

Вариант классический

a[a.length-1]

Все просто, без объяснений. Но слишком просто. Без креатива и души =)

Вариант slice()

Метод slice() возвращает новый массив, содержащий копию части исходного массива.

a.slice(-1)[0] // = 4
// или
a.slice(-1).pop()

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

a.slice(-2, -1)[0]  // = 3

Деструктуризация

Вариант скорее про возможности и красоту многообразия JS:

const [last] = a.slice(-1)
console.log(last)

Но почему бы и нет, м? В принципе даже очень ок, если вы собираетесь в итоге значение куда-то присвоить.

Данный вариант получает приз зрительских симпатий, так как он имеет право на жизнь и даже право на то, чтобы попасть в продакшен.

Array.pop

Взять значение последнего элемента можно и через метод pop() , но у него есть но. Он изменяет текущий массив. Но что если:

[...a].pop()

Это уже скорее “спортивный” вариант, который можно использовать в различных челенджах и головоломках. Но если подходить формально — задача решена. В принципе если захотеть, то можно нагенерить еще кучу разновидностей подобного рода. Array.from и все такое…

Reverse

Этот метод скорее просто показан что так тоже можно, но уж точно не нужно.

a.reverse()[0]

Шутка ли, но я когда-то такое в боевом проекте видел (или в npm пакете).

reduceRight

Метод reduceRight() применяет функцию к аккумулятору и каждому значению массива (справа-налево), сводя его к одному значению.

a.reduceRight((a,i)=>a||i)

Выглядит уже как магия, но по факту никакой магии. Но это явно и не самый короткий вариант, неочевидный, да и просто неоптимальный. Но он имеет право на жизнь ибо он решает нашу задачу.

Данный вариант получает приз за самую большую когнитивную нагрузку.

Если ваш проект будет обиловать таким кодом, его захотят переписать с нуля. Возможно вы этого и хотите, а? 😉

jQuery

Внезапно, да? Но если вдруг у вас уже проект на JQ, то пользуйтесь его мощью:

$([1,2,3,4]).get(-1) // = 4

И да, JQ это не стыдно, если что. Он решает свой пул задач и очень даже хорошо.

Строки

Все вышеописанное работает и для строк, так как строки — это array-like объекты. Они имеют длину и реализуют интерфейс итератора. Так что вы даже итерироваться можете по ним:

for (let s of "abc") {
console.log(s)
}

Таким образом со строками все тоже самое:

"abcdef".slice(-1).pop()
const [last] = "abcdef".slice(-1)

Кроме методов map, reduce и им подобным. Если очень хочется, строку придется сначала конвертнуть в массив:

[..."abcdef"].reduceRight((a,i)=>a||i)

Будьте осторожны, за такой код вас могут сжечь на костре.


Аштшыр

— что означает Finish, если переключить раскладу на клавиатуре. Думаю что хватит. Вообще хотел немного про другое рассказать, но вдруг оказалось что простой вопрос превратился в лонгрид. Про списки в JavaScript я буду еще много говорить. Мне приходится работать со списками очень много и гонять их в хвост и гриву, сортировать, фильтровать и чего только не делать с ними почти что каждый день.