Автор оригинала: 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 рядом с вами.