Короткие и приятные приемы, чтобы держать их в заднем кармане

На этой неделе О’Рейли выпустил третье издание Поваренной книги JavaScript, которое теперь полностью обновлено современными функциями и методами. Я знаю это, потому что я написал часть этого контента вместе со своим звездным соавтором Адамом Скоттом.

В ознаменование этого выпуска я решил собрать несколько моих любимых фрагментов JavaScript. Я не говорю о массивных функциях, фреймворках или автоматически сгенерированном коде. Я даже не говорю о новых языковых нововведениях или способах повышения продуктивности. Я говорю об умных маленьких кодлетах, которые делают жизнь лучше. Те, которые сокращают 12 строк до 2 или упрощают написание чистого, понятного кода. Я уверен, что у вас тоже есть собственный запас трюков - и, возможно, вы найдете новую идею для сбора в этом списке.

1. Использование символа для создания перечисления

Вы, вероятно, знакомы с Symbol, необычным объектом JavaScript, который имеет единственную цель в жизни: предоставление случайного идентификатора, который гарантированно будет уникальным в глобальном масштабе. В Symbol есть несколько интересных (и узкоспециализированных) приложений для расширяемости и метапрограммирования. Но он также является хорошим способом создания перечисления - группы именованных констант, - которые язык JavaScript изначально не поддерживает.

Вот пример с конструкцией типа enum под названием TrafficLight:

В этом примере каждое значение перечисления (например, TrafficLight.Green) получает уникальное значение. Но на самом деле вы никогда не увидите это значение, потому что Symbol сохраняет его полностью непрозрачным. Поэтому, если вам нужно сериализовать эти данные за пределами вашего приложения (например, сохранить их на диске или отправить по сети), это, вероятно, не тот подход, который вам нужен.

2. Безболезненно протестируйте код в консоли

Загрузка тестовой страницы JavaScript занимает всего несколько секунд. Но иногда мне хочется опробовать одну отдельную функцию JavaScript. Будет еще полезнее, если я смогу поработать над этим тестовым фрагментом кода в браузере рядом со статьей, которую я читаю.

Теперь нет ничего волшебного в вызове DevTools вашего браузера (F12 в Windows и Cmd-Shift-J или Cmd-Option-J в macOS, в зависимости от браузера). И нет ничего волшебного в том, чтобы вводить код в консоль JavaScript - просто не забывайте Shift+Enter для каждого разрыва строки и нажимайте Enter, чтобы запустить готовый код. Но если вы хотите повторить пример (набрать его один раз, отредактировать, запустить повторно и т. Д.), Вам необходимо контролировать объем выполнения кода.

Лучший способ сделать это - заключить весь блок кода в фигурные скобки { }. Таким образом, вы можете запустить свой код (нажмите Enter), вызвать его снова (нажмите стрелку вверх), отредактировать и перезапустить, и все это без раздражающей ошибки «Идентификатор уже объявлен».

Поэтому вместо того, чтобы набирать это:

let testValue = 40+12;
console.log(testValue);

Вы хотите это:

{
let testValue = 40+12;
console.log(testValue);
}

Легкий!

3. Глубоко скопируйте массив в одну строку.

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

Array.map() может делать много трюков, но клонирование массива - один из наиболее полезных. Чтобы увидеть, как это работает, представьте, что вы создаете такой массив с двумя объектами:

const objectsOriginal = [{name: 'Sadie', age: 12},
                         {name: 'Patrick', age: 18}];

Теперь предположим, что вы хотите скопировать эти объекты. Этот код вам не нужен:

// All this gets you is two variables pointing to the same array
const objectsCopy = objectsOriginal;

Это немного лучше, но все равно не дает того, что вам нужно:

// Creates two array objects, but they share the same people objects
const objectsCopy = [...objectsOriginal];

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

Теперь вот решение с Array.map(), которое берет каждый элемент, расширяет объект, а затем создает дубликат объекта с теми же свойствами:

const objectsCopy = objectsOriginal.map(element => ({...element}));

Вот полная демонстрация техники:

Конечно, есть некоторые оговорки. Это однослойная глубокая копия, поэтому, если ваши объекты содержат ссылки на другие объекты, они не дублируются. В такой ситуации лучше формализовать логику клонирования, создав собственный класс и написав собственный clone() метод. Затем вы можете использовать Array.map() для вызова этого clone() метода:

const objectsCopy = objectsOriginal.map(element => element.clone());

4. Очистите массив в одну строку.

Раз уж мы говорим о массивах, вот еще один полезный трюк. Иногда вы хотите очистить объект массива, не заменяя его новым пустым массивом (возможно, потому, что на него ссылается другой объект). Прежде чем вы начнете повторять и вызывать Array.remove(), вот ярлык, который работает путем установки свойства length:

const numbers = [2, 42, 5, 304, 1, 13];
numbers.length = 0;
// The array is now empty

Если вы изучаете традиционный язык ООП, это может показаться странным, потому что Array.length похоже на свойство, которое должно быть доступно только для чтения, а установка свойства обычно не должна запускать операцию (например, удаление элементов). Но в JavaScript иногда вы просто делаете то, что вам нравится.

5. Дайте вашему объекту разумное строковое представление.

Устали видеть «[объект Object]» в консоли браузера, когда вы показываете его с помощью console.log()? Вы можете легко изменить это поведение, предоставив своему объекту респектабельный toString() метод. Вот пример:

И снова JavaScript удаляет часть инфраструктуры, которую вы видели в классическом языке ООП. (Например, нет ключевого слова override.) Но оно работает.

6. Поддержка цепочки методов в ваших классах

Цепочка методов на самом деле не считается уловкой, но это одна из тех практик, которую мы не всегда думаем поддерживать, и она может сэкономить вам время. Не менее важно то, что он перекликается с образом жизни JavaScript, потому что многие встроенные объекты используют его для хорошего эффекта. Рассмотрим этот пример с объектом Array. Здесь цепочка методов позволяет объединить две операции в одну строку - конкатенацию массивов и сортировку массивов:

const evens = [2, 4, 6, 8];
const odds = [1, 3, 5, 7, 9];
const evensAndOdds = evens.concat(odds).sort();
console.log(evensAndOdds); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

Самый простой способ поддержать цепочку методов в ваших собственных классах - просто вернуть ссылку на текущий объект с ключевым словом this. Этот Book класс использует эту технику в своих raisePrice() и releaseNewEdition() методах:

Функциональные программисты посмотрят на это и скажут, что, возможно, вам вообще не нужен объект с состоянием, а неизменяемый объект, который продолжает возвращать копии, как это делают Array.concat() и Array.sort(). Если этот подход имеет смысл для вашей кодовой базы, просто верните новый объект с измененными деталями вместо текущего экземпляра в конце метода, например:

raisePrice(percent) {
  const increase = this.price*percent;
  return new Book(this.title, this.author,
   this.price + Math.round(increase)/100, this.date);
}

7. Составьте повторяющийся список случайных чисел.

Этот немного более специализированный, но в крайнем случае мне он пригодился.

Есть несколько разных способов создания псевдослучайных чисел в JavaScript. Стандарт Math.random() получает случайные значения, которые не являются криптографически безопасными, что подходит для большинства случаев. Если нет, то есть менее известные Crypto.getRandomValues(), которые могут вам помочь.

Но оба этих подхода дают вам неповторимые случайные числа. Это не то, что вам нужно, если вы хотите запустить повторяемый тест или моделирование, что важно для множества статистических и научных операций. В этой области можно очень углубиться и усложнить, но я всегда использую простой и невероятно быстрый алгоритм Mulberry32, чтобы выдавать мне псевдослучайные числа, которые полностью детерминированы (что означает, что если вы начнете с одного и того же начального числа, вы всегда получите один и тот же список). ценностей). И я завершаю это функцией генератора, которая является одной из моих любимых специализированных функций JavaScript. Вот код:

Вам не нужно понимать часть этой реализации со сдвигом битов, которая заимствована из классической реализации C. Особенность JavaScript заключается в том, что это функция generator, что обозначено звездочкой в ​​ключевом слове function*. Функции генератора используют yield для возврата значений по запросу - в данном случае случайных чисел.

Вот как вы создаете и вызываете генератор:

Эта функция генератора завершает бесконечный цикл, который выполняется до тех пор, пока вы продолжаете вызывать next(). Если случайное число не требуется, выполнение генератора приостанавливается, а все его состояние остается неизменным. Конечно, вам не нужна функция генератора для создания списка случайных чисел, но это элегантное решение.

Если вам понравились эти примеры, ознакомьтесь с Поваренной книгой JavaScript, где вы найдете больше идей для миниатюрного кода. Или подпишитесь на Информационный бюллетень Young Coder, чтобы получать ежемесячные электронные письма с нашими лучшими статьями.