Рубрики
Без рубрики

Первый должен быть последний с массивами JavaScript

FOMAS CARRASSO Первый должен быть в последний раз с JavaScript Arrayssea Salps, формируя естественные «массивы», поэтому последний должен быть [0], а первая [длина – 1]. – Адаптирован из Матфея 20: 16i, пропускаю мальтузию К нему: массивы являются одним из простейших и наиболее важных данных

Автор оригинала: FreeCodeCamp Community Member.

от Thomas Carrasso

Я пропущу мальтузийскую катастрофу и добраться до него: массивы являются одной из самых простых и важнейших структур данных. Хотя элементы терминала (первый и последний и последний) часто обращаются, JavaScript не предоставляет удобного свойства или способа для этого, и использование индексов может быть избыточным и склонным к побочным эффектам и Ошибка Off-One Отказ

Меньшее известный, javaScript TC39 Предложение Предлагает утешение в виде двух «новых» свойств: Array.lastitem & Array.lastindex Отказ

Массивы JavaScript

Во многих языках программирования, включая JavaScript, массивы с нулевым индексированным. Элементы терминалов – сначала и последствия доступны через [0] и [Длина - 1] Индексы соответственно. Мы обязаны этому удовольствием для Прецедент, установленный C , где индекс представляет собой смещение от головки массива. Это делает ноль первым индексом, потому что это это голова массива. Также Dijkstra провозгласил ” нулю как самое естественное число. ” Так что дайте ему написано. Так что позвольте это сделать.

Я подозреваю, если вы усреднены доступа по индексу, вы обнаружите, что элементы терминалов ссылаются чаще всего. В конце концов, массивы обычно используются для хранения отсортированной коллекции и делают это местами превосходные элементы (самые низкие, самые низкие, самые старые, новейшие и т. Д.) На концах.

В отличие от других языков сценариев (скажем, PHP или Elixir ), JavaScript не предоставляет удобный доступ к элементам массива клемм. Рассмотрим тривиальный пример обменивания последних элементов в двух массивах:

let faces = ["?", "?", "?", "?", "?"];let animals = ["?", "?", "?", "?", "?"];  
let lastAnimal = animals[animals.length - 1];animals[animals.length - 1] = faces[faces.length - 1];faces[faces.length - 1] = lastAnimal;

Переменная логика требует 2 массивов, ссылающихся в 8 раз в 3 строки! В реальном мировом коде это может быстро стать очень повторяющимся и трудно для человека разбираться (хотя оно совершенно читаемо для машины).

Более того, исключительно использует индексы, вы не можете определить массив и получить последний элемент в том же выражении. Это может показаться не важно, но рассмотрим еще один пример, где функция, GetLogins () делает асинхронный API вызов и возвращает отсортированный массив. Предполагая, что мы хотим самое последнее событие входа в систему в конце массива:

let lastLogin = async () => {  let logins = await getLogins();  return logins[logins.length - 1];};

Если длина не закреплена и известна заранее, мы есть Чтобы назначить массив локальной переменной для доступа к последнему элементу. Один общий способ обратиться к этому на языках, таких как Python и Ruby это использовать негативные показатели. Тогда [Длина - 1] Может быть сокращен до [-1] Снятие необходимости местной ссылки.

Я нахожу -1 только незначительно читабелее, чем Длина - 1 И хотя можно приблизить Индексы негативных массивов в JavaScript с ES6 прокси или Array.slice (-1) [0] , оба приходят с Значительные последствия производительности За то, что в противном случае должно быть простым случайным доступом.

Подчеркивание и лодаш

Одним из самых известных принципов разработки программного обеспечения является не повторять себя (сухой). Поскольку доступ к тому, что элементы терминалов настолько распространены, почему бы не написать функцию помощника, чтобы сделать это? К счастью, многие библиотеки, такие как Подчеркивание и Лоташ уже предоставляют утилиты для _.first & _.last Отказ

Это предлагает большое улучшение в lastlogin () Пример выше:

let lastLogin = async () => _.last(await getLogins());

Но когда дело доходит до примера замены последних элементов, улучшение менее значимо:

let faces = ["?", "?", "?", "?", "?"];let animals = ["?", "?", "?", "?", "?"];  
let lastAnimal = _.last(animals);animals[animals.length - 1] = _.last(faces);faces[faces.length - 1] = lastAnimal;

Эти функции утилиты удалены 2 из 8 ссылок, только теперь мы представили внешнюю зависимость, которая, как ни странно, не включает функцию для Настройка Элементы терминалов.

Скорее всего, такая функция сознательно исключена, потому что его API будет запутана и трудно читаться. Ранние версии Лодаша предоставили метод _.last (массив, n) где N Было ли количество предметов с конца, но в конечном итоге было удалено в пользу _ake (массив, n) Отказ

Предполагая Nums это массив чисел, что было бы ожидаемое поведение _.last (nums, n) ? Это может вернуть последние два элемента, такими как _ake или может установить значение последнего элемента, равного N Отказ

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

let nums = ['d', 'e', 'v', 'e', 'l']; // set first = last
_.first(faces, _.last(faces));        // Lodash style
$(faces).first($(faces).last());      // jQuery style
faces.first(faces.last());            // prototype

Я не нашел ни одного из этих подходов, чтобы быть большим из улучшения. На самом деле, здесь что-то важное потеряно. Каждый выполняет задание, но нет, используйте оператор присваивания ( = ). Это может быть сделано более очевидно с именомочными конвенциями, такими как Гетласть и SetFirst , но это быстро становится чрезмерно многословным. Не говоря уже о Пятый круг ада Полноработает программистов, вынужденных навигации на «самодоступный» наследный код, где единственный способ доступа или модификации данных проходит через GetTers и Setters.

Как-то, похоже, мы застряли с [0] & [Длина - 1]

Или мы? ?

Предложение

Как уже упоминалось, предложение по техническому кандидату (TC39) Ecmascript пытается решить эту проблему, определение двух новых свойств на Массив Объект: Фастем & LastIndex Отказ Это предложение это уже поддерживается в Core-JS 3 И пригодным для использования сегодня в Babel 7 & Typescript. Даже если вы не используете транспортер, это предложение включает в себя Polyfill Отказ

Лично я не нахожу много ценности в LastIndex и предпочитаю более короткие именования Ruby для Первый и Последнее , хотя это было исключено из-за Потенциальные проблемы веб-совместимости Отказ Я также удивлен, что это предложение не предлагает firstiTem Собственность для согласованности и симметрии.

В промежуточном состоянии я могу предложить никакую зависимость, подход Ruby-Esque в ES6:

Первый Последний

Теперь у нас есть два новых свойства массива- Первый & Последнее -И решение, которое:

✓ использует оператор назначения

✓ не клонирует массив

✓ Может определить массив и получить клеммный элемент в одном выражении

✓ читается ли человеком

✓ Предоставляет интерфейс для получения и настройки

Мы можем переписать lastlogin () снова в одной строке:

let lastLogin = async () => (await getLogins()).last;

Но настоящая победа приходит, когда мы поменяем последние элементы в двух массивах с половиной числа ссылок:

let faces = ["?", "?", "?", "?", "?"];let animals = ["?", "?", "?", "?", "?"];  
let lastAnimal = animals.last;animals.last = faces.last;faces.last = lastAnimal;

Все идеально, и мы решили одну из самых сложных проблем CS. Там нет злых заветов, скрывающихся в этом подходе …

Прототип паранойя

Многие считают Расширение прототипа родного объекта анти-шаблон И преступность наказывается на 100 лет программирования в Java. До внедрения перечислимый Собственность, Расширение Объект. Прототип может изменить поведение для в петли. Это также может привести к конфликту между различными библиотеками, рамками и сторонние зависимостями.

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

let faces = ["?", "?", "?", "?", "?"];let ln = faces.length  
faces.lst = "?"; // (5) ["?", "?", "?", "?", "?", lst: "?"]  
faces.lst("?");  // Uncaught TypeError: faces.lst is not a function 
faces[ln] = "?"; // (6) ["?", "?", "?", "?", "?", "?"]  

Эта проблема не уникальна для нашего подхода, он применяется ко всем прототипам родных объектов (включая массивы). Тем не менее, это предлагает безопасность в другой форме. Массивы в JavaScript не фиксируются по длине и, следовательно, нет IndexoutOfboundsexceptions Отказ Использование Array.last гарантирует, что мы не случайно пытаемся получить доступ [Длина] и непреднамеренно войти undefined Территория.

Независимо от того, какой подход вы берете, есть подводные камни. Еще раз, программное обеспечение оказывается искусство делать компромиссы Отказ

Продолжая с посторонней библейской ссылкой, предполагая, что мы не считаем расширением Array.Prototype Является ли вечный грех или мы готовы откусить запретный плод, мы можем использовать этот краткий и читаемый синтаксис сегодня!

Последние слова

На языках сценариев, таких как JavaScript, я предпочитаю код, который функциональный, краткий и читаемый. Когда дело доступа к доступу к элементам клеммных массивов, я нахожу Array.last Недвижимость быть самым элегантным. В производственном предельном приложении я мог бы любить Lodash, чтобы минимизировать проблемы конфликта и кросс-браузера. Но в узлах в задних сервисах, где я контролирую среду, я предпочитаю эти пользовательские свойства.

Я, конечно, не первый , и я не буду последним, чтобы оценить ценность (или осторожность в отношении последствий) свойств, таких как Array.lastitem , который, надеюсь, скоро придет на версию Ecmascript рядом с вами.

Следуй за мной на LinkedIn · Github · Середина