Я покажу вам простой способ расширить дефицит функций JavaScript, написав свои собственные функции и поместив их в виде пакетов в npm, чтобы вы могли легко использовать их в каждом из своих проектов.

Проблема

JavaScript, особенно до возрождения ES6, был крайне беден с точки зрения доступности стандартных библиотек. Никаких map для массивов, никакой интерполяции строк, действительно очень лаконичный язык!

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

Рассмотрим реальный пример:

Это выдержка из сложного компонента react.js. Что не так с этим кодом? Этот фрагмент кода у меня не сработал, потому что у объекта collectorGroup нет свойства targets_count, вместо этого у него есть target_count. Довольно простая опечатка, не так ли? Но это приводит к сравнению collectorGroup.targets_count который return undefined с целым числом (10, как определено в компоненте), так что в результате я трачу несколько часов на выяснение, почему collectorGroupHasFewCircles всегда было ложным — оператор undefined < 10 вернет ложь.

Поиск

Уже есть существующие решения. Несколько из них:

  • Используйте средства проверки статических типов на уровне компиляции, такие как flow или TypeScript — это синтаксический сахар над JavaScript, позволяющий заранее определять типы.
  • Используйте react-proptypes с его функцией shape:

Однако оба решения имеют схожий недостаток. Вы должны определить все свойства большого объекта collectorGroup. Это довольно просто, если у него есть, скажем, несколько свойств. Но на самом деле их очень много. Поэтому такие решения мне не подходят. Что я должен делать?

Здесь можно было бы придумать большую кучу решений, но я решил использовать самое простое. Мы должны определить функцию, которая принимает объект и имя его свойства и возвращает значение для этого свойства. Если свойства нет, должна выдаваться ошибка. Вот как работает Hash#fetch в Ruby:

Беглый поиск в гугле показывает, что решение уже есть: zealit. Его API выглядит так:

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

Решение

Решением будет чистая функция objectFetch(object, propertyName) , которая принимает объект и имя свойства и либо возвращает значение для этого свойства, либо выдает ошибку, если такого свойства в объекте нет. На самом деле, функция довольно проста:

Мы немного расширили JavaScript, написав крошечную функцию, которая делает то, что объявляет. Мы могли бы легко извлечь его в папку utils проекта. Но можем ли мы сделать больше? Я думаю, мы могли бы.

Расширения JavaScript чрезвычайно широко распространены. Допустим, вы в конечном итоге будете использовать некоторые части Lodash почти во всех своих проектах. Мы должны опубликовать наш objectFetch в npm.

Издательский

Новый пакет будет довольно простой функцией, не будем здесь изобретать велосипед. Просто используйте стартовый комплект со всеми включенными батареями. Так как я большой поклонник TypeScript, давайте воспользуемся стартовым набором, который я считаю наиболее полезным — это typescript-starter Джейсона Дрейзенера. Не беспокойтесь об используемом здесь TypeScript, он будет опубликован как чистый javascript, поэтому мы можем легко импортировать его в любой файл JavaScript. Вы можете использовать es6-starter-kit, если вам так нужен чистый JavaScript.

Убедитесь, что у вас установлена ​​последняя версия npm (она содержит команду npx), и запустите:

npx typescript-starter

Это инициализирует typescript-starter проект, настроенный для вас. Вы будете руководствоваться командной строкой, чтобы выбрать параметры проекта, которые лучше всего подходят для вас:

? 📦 Enter the new package name: object-fetch
? 🔨 What are you making? Javascript library
? 💬 Enter the package description: fetch object's property by its name or throw error
? 🚄 Will this project use npm or yarn? npm
? 📚 Which global type definitions do you want to include? None — the library won't use any globals or modules from Node.js or the DOM
? 🚀 More fun stuff: Enable tslint-immutable, Include VS Code debugging config, Include CircleCI config

Давайте избавимся от всего, что связано с приборами, и оставим всего несколько файлов. Это очень маленькая библиотека, поэтому должно существовать только src/index.ts:

Мы должны покрывать код тестами вне зависимости от количества строк. Итак, src/index.spec.ts тоже должен существовать:

И это все! Ни сложной настройки набора тестов, ни конфигурации машинописного текста. Стартовый комплект сделает всю тяжелую работу за вас, поэтому ваша работа будет сосредоточена только на вашем коде. Запустите npm run test и увидите, что все 2 теста пройдены. Пришло время опубликовать нашу библиотеку объектной выборки. npm run publish делает всю работу, поэтому у нас есть пакет объектной выборки, опубликованный на npm.

Просто добавьте object-fetch в свой существующий проект, и все готово. Окончательный код будет выглядеть так:

Вуаля! Проблемная строка приведет к ошибке ReferenceError, уведомляющей разработчика об отсутствии такого свойства targets_count в объекте collectorGroup.

Резюме

Теперь вы должны сейчас:

  • как расширить недостающую стандартную функциональность JavaScript
  • как извлечь функции расширения JavaScript в npm.

Удачного JavaScript!