Безопасность JavaScript или как написать безопасный код на JS. Тесное взаимодействие между JavaScript и DOM

Представляет собой модульный упаковщик, который создаёт граф зависимостей со всеми модулями для приложения на JavaScript. Webpack упаковывает модули в один или несколько маленьких пакетов для загрузки браузером. Кроме того, Webpack может использоваться в качестве средства запуска задач, так как он анализирует зависимости между модулями и образовывает ресурсы (ассеты). Подробнее с использованием Webpack в своих проектах вы можете ознакомиться в нашей .

  • Grunt - таск раннер, предназначенный для автоматизации повторяющихся и трудоёмких задач, которые отнимают много времени. В его программной экосистеме существует огромное количество плагинов (более 6000).
  • Gulp - не очередной диспетчер запуска задач, а инструмент с интересным подходом: он определяет задачи в JavaScript как функции, также GUl автоматизирует «болезненные» задачи, предлагая обширную программную экосистему (более 2700 плагинов), также он обеспечивает лучшую прозрачность и контроль над процессом.
  • Browserify позволяет разработчикам программного обеспечения использовать модули стиля NodeJS в браузерах. Вы определяете зависимости, а Broweserify упаковывает всё это в аккуратный JS-файл.
  • Brunch.io - инструмент, основными идеями которого являются скорость и простота. Он поставляется с простой конфигурацией и подробной документацией для быстрого запуска. Brunch автоматически создаёт карту JS-файлов вместе с таблицами стилей CSS, что упрощает процесс отладки на стороне клиента.
  • Yeoman - универсальный инструмент, который может использоваться с почти любым языком программирования (JavaScript, Python, C#, Java и прочие). Эта базовая система кодогенерации с богатой программной экосистемой (более 6200 плагинов) служит для разработки веб-приложений. Благодаря Yeoman вы можете быстро создавать новые проекты, не забывая об обслуживании и улучшении уже существующих.
  • IDE и редакторы кода

    • Swagger - это набор правил и инструментов для описания API. Инструмент представляет собой языконезависимую утилиту. Это значит, что Swagger создаёт чёткую документацию, которая читается одинаково хорошо как человеком, так и машиной, позволяя автоматизировать процессы зависящие от API.
    • JSDoc - набор инструментов, автоматически создающий многостраничную текстовую документацию (HTML, JSON, XML и т. д.) из комментариев из исходного кода на JavaScript. Это приложение может пригодиться для управления крупномасштабными проектами.
    • jGrouseDoc (jGD) - это гибкий инструмент с открытым исходным кодом, который позволяет разработчикам генерировать API из комментариев из исходного кода на JavaScript. jGD документирует не только переменные и функции, но и пространства имён, интерфейсы, пакеты и некоторые другие элементы.
    • YUIDoc - приложение, написанное на NodeJS. Оно использует синтаксис, подобный тому, который применяется в Javadoc и Doxygen. Также инструмент может похвастаться поддержкой предварительного просмотра в реальном времени, расширенной поддержкой языка и продвинутой разметку.
    • Docco - бесплатный инструмент для документации, написанный на «литературном» CoffeeScript. Он создаёт HTML-документ для отображения ваших комментариев, чередующихся с кодом. Следует отметить, что инструмент поддерживает не только JavaScript, но и другие языки. Например, Python, Ruby, Clojure и прочие.

    Инструменты тестирования

    Инструменты тестирования для JavaScript созданы для обнаружения ошибок на этапе разработки, чтобы избежать в будущем ошибок у пользователей. С ростом сложности пользовательских приложений автоматические тесты не только повышают производительность приложения, но и помогают компаниям сохранить бюджет.

    • Jasmine - BDD-фреймворк (Behavior-driven Development - разработка на основе поведений) служит для тестирования JS-кода. У него нет внешних зависимостей, и он не требует запуска DOM. Jasmine имеет чистый и понятный синтаксис, что позволяет ускорять и упрощать тестирование. Также фреймворк может использоваться для тестирования кода Python и Ruby.
    • Mocha - это функциональная тестовая среда, работающая на Node.js в браузере. Она проводит тесты последовательно для обеспечения гибкой и точной отчётности, делая асинхронные тесты весёлыми и лёгкими. Mocha часто используется вместе с Chai для проверки результатов теста.
    • PhantomJS часто используется для интерфейсных тестов и юнит-тестов. Учитывая то, что это что-то вроде «безголового» WebKit, скрипты выполняются намного быстрее. Также он включает в себя встроенную поддержку различных веб-стандартов. Например, JSON, Canvas, обработку DOM, SVG и селекторы CSS.
    • Protractor - это сквозной тестовый фреймворк, написанный на Node.js для тестирования приложений на AngularJS и Angular. Он был создан на основе WebDriverJS и проверяет приложения подобно конечному пользователю, используя специальные драйвера и встроенные события.

    Инструменты отладки

    Отладка кода - довольно трудоёмкий и поглощающий время процесс для JavaScript-разработчиков. Инструменты для отладки кода будут особенно полезны при работе с тысячами строк кода. Многие из инструментов отладки обеспечивают довольно точные результаты.

    • JavaScript Debugger - инструмент от сообщества разработчиков Mozilla (MDN), который может быть использован как автономное веб-приложение для отладки кода в разных браузерах. Firefox предлагает локальные и удалённые функциональные возможности, а также возможность отладки кода на Android-устройстве с помощью Firefox для Android.
    • Chrome Dev Tools - набор инструментов, включающий в себя несколько утилит для отладки кода JavaScript, редактирования CSS и тестирования производительности приложений.
    • ng-inspector - кроссбраузерное расширение, которое призвано помочь разработчикам с написанием, пониманием и отладкой приложений на AngularJS. Утилита поставляется с обновлениями в реальном времени, подсветкой DOM, прямым доступом к областям, моделям и прочим элементам приложения.
    • Augury - расширение для браузера Google Chrome и отладки приложений на Angular 2. Оно позволяет разработчикам приложений на Angular 2 напрямую анализировать структуру приложения и рабочие характеристики, а также позволяет обнаружить изменения.

    Инструменты безопасности

    • Snyk - коммерческий инструмент для обнаружения, исправления и предотвращения известных уязвимостей в приложениях на JavaScript, Java и Ruby. Служба имеет собственную базу данных уязвимостей и берёт данные из NSP и NIST NVD. Патчи и обновления, которые предлагает компания, позволяют разработчикам предупредить риски, связанные с безопасностью.
    • Node Security Project предлагает полезные инструменты для сканирования зависимостей и обнаружения уязвимостей. NSP использует свою собственную базу данных, построенную на сканировании модулей npm, а также данные из общих баз данных, таких как NIST NVD (National Vulnerability Database). Кроме того, NSP обеспечивает интеграцию с программным обеспечением GitHub Pull Request и CI. Также имеется проверка в реальном времени, предупреждения и рекомендации по устранению уязвимостей в приложениях на Node.js.
    • RetireJS - это средство проверки зависимостей с открытым исходным кодом. Включает в себя различные компоненты, такие как сканер командной строки, плагин Grunt, расширения Firefox и Chrome, плагины Burp и OWASP ZAP. Retirejs собирает информацию об уязвимостях из NIST NVD и других источников, таких как системы отслеживания ошибок, блоги и списки рассылки.
    • Gemnasium - это коммерческий инструмент с бесплатной пробной версией. Он поддерживает различные технологии и пакеты, включая Ruby, PHP, Bower (JavaScript), Python и npm (JavaScript). Инструмент безопасности Gemnasium поставляется с полезными функциями, такими как автоматическое обновление, оповещения в реальном времени, уведомления о безопасности и интеграция с сервисом Slack.
    • OSSIndex поддерживает различные экосистемы (Java, JavaScript и.NET / C #) и множество платформ, таких как NuGet, npm, Bower, Chocolatey, Maven, Composer, Drupal и MSI. Он собирает информацию об уязвимостях из Национальной базы данных уязвимостей (NVD) и отзывов. Также он обрабатывает информацию от членов сообщества.

    Инструменты аналитики и оптимизации кода

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

    В настоящее время в современном программном обеспечении объединяются инструменты анализа статического кода во время разработки, чтобы исключить попадание некачественного кода в продакшен.

    • JSLint - это аналитический веб-инструмент для проверки качества кода JavaScript. Как только он обнаруживает проблему в источнике, он возвращает сообщение с описанием проблемы и приблизительным местоположением в коде. JSLint способен анализировать некоторые нормы стиля и раскрывать синтаксические ошибки и структурные проблемы.
    • JSHint - гибкий инструмент, развивающийся сообществом, для обнаружения ошибок и потенциальных проблем в вашем JS-коде, кроме того, JSHint - форк от JSLint. Основная цель этого инструмента статического анализа кода - помощь разработчикам JavaScript, работающим над сложными программами. Он способен обнаруживать ошибки синтаксиса, неявное преобразование типов данных или отсутствие переменной. Однако он не может определить скорость и правильность работы вашего приложения, как и не сможет определить проблемы с памятью в вашем приложении. JSHint - форк от JSLint.
    • ESLint – это линтер с открытым исходным кодом для веб-приложений JSX и JavaScript. Он помогает обнаруживать сомнительные шаблоны или находить код, который не соответствует конкретным стилям. Это позволяет разработчикам обнаруживать ошибки в JS-коде без его выполнения, тем самым экономя время. Будучи написанным на Node.js, инструмент предлагает оперативную среду выполнения и плавную установку через npm.
    • Flow - статический контролёр кода для JavaScript, разработанный компанией Facebook. Он использует аннотации статического типа для проверки кода на предмет ошибок. Типы - параметры, установленные разработчиками, а Flow проверяет ваше программное обеспечение на соответствие требованиям.

    Инструменты управления версиями

    • В последние годы Git стала широко используемой системой контроля версий как для небольших, так и для крупных проектов. Эта бесплатная утилита обеспечивает отличную скорость работы и эффективность. Её популярность объясняется распределённой системой и различными типами элементов управления, а также промежуточной областью, где версии могут быть просмотрены и отформатированы непосредственно перед завершением фиксации.
    • Инструмент Subversion или SVN приобрёл огромную популярность, и он по-прежнему широко используется в проектах с открытым исходным кодом и такими платформами, как Python Apache или Ruby. Этот CVS поставляется со множеством функций, позволяющих управлять различными операциями (переименование, копирование, удаление и т. д.), слияниями, блокировкой файлов и многим другим.

    Инструменты управления пакетами и зависимостями

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

    Разработка безопасных приложений на JavaScript - довольно сложное занятие. Но вполне выполнимое. В сегодняшней статье мы рассмотрим особенности JavaScript, из-за которых проблемы с безопасностью и поговорим про , которые помогут их избежать.

    Почему сложно писать безопасный код на JS

    Итак, вот 5 причин, почему сложно писать безопасный код на JS

    Компилятор не поможет

    JavaScript - интерпретируемый язык. А это значит, что компилятор не будет все время на что-нибудь жаловаться, отказываясь работать и подталкивая тебя поправить ошибки и оптимизировать код.

    Динамическая суть JavaScript

    JavaScript динамический, слаботипизированный и асинхронный. А это все признаки того, что попасть в беду легче легкого.

    1. Языковые средства вроде eval и включения стороннего кода через script src позволяют исполнять строки прямо в рантайме. Как следствие - сложно дать «статические гарантии» того, что код будет вести себя определенным образом. Динамический анализ это тоже затрудняет (см. научную работу).

    Использование eval

    2. Слабая типизация приводит к тому, что применять устоявшиеся методы статического анализа непросто - по крайней мере в сравнении со статически типизированными языками (например, Java).

    3. Асинхронные колбэки, вызовы которых JavaScript допускает через механизмы вроде setTimeout и XMLHttpRequest (тот самый знаменитый AJAX), по статистике прячут в себе больше всего коварных ошибок.

    Замысловатые возможности JS

    Чего только не притащили в JavaScript с годами! В частности, в нем есть прототипы , функции первого класса и замыкания . Они делают язык еще динамичнее, а написание безопасного кода - сложнее.

    1. Прототипы. Смысл их в том, что программы пишутся в духе объектно ориентированного подхода, но без использования классов. При таком подходе объекты наследуют необходимые им свойства напрямую от других объектов (прототипов). При этом в JS прототипы могут быть переопределены прямо в рантайме. И если это переопределение случилось, то эффект сразу же распространяется на все объекты, которые наследуют свойства переопределяемого прототипа.

    Как обрабатываются прототипы

    Справедливости ради надо сказать, что в новых спецификациях ECMAScript классы тоже присутствуют.

    2. Функции первого класса. У JS очень гибкая модель объектов и функций. Свойства объектов и их значения могут быть созданы, изменены или удалены прямо в рантайме, и ко всем есть доступ через функции первого класса.

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

    Из-за такой гибкости и динамичности JavaScript (см. пункты 1 и 3) определение набора всех доступных свойств объекта при статическом анализе - неразрешимая задача. Однако веб-разработчики повсеместно используют динамические особенности языка, а соответственно, пренебрегать ими при анализе кода нельзя. Иначе какая тут гарантия безопасности?

    Тесное взаимодействие между JavaScript и DOM

    Это нужно, чтобы обеспечить «бесшовное» обновление веб-страницы, прямо в рантайме. DOM, как известно, представляет собой стандартную объектную модель, нейтральную по отношению к платформам и языкам, которая предназначена для отрисовки документов HTML и XML. У DOM есть собственный API для работы с отображаемым документом: для динамического доступа, перемещения и обновления отображаемого документа (его содержимого, структуры и стиля). Изменения в DOM могут вноситься динамически, через JavaScript. И эти изменения сразу же отображаются в браузере.

    Благодаря DOM загруженные в браузер веб-страницы можно обновлять поэтапно по ходу подгрузки данных с сервера. Однако у такого удобства есть и оборотная сторона: фрагменты кода, которые отвечают за динамическое взаимодействие между JS и DOM, особенно подвержены ошибкам.

    Наиболее распространенные ошибки в веб-приложениях

    Сложные событийные взаимодействия

    JavaScript - это язык, управляемый событиями (event-driven). Он позволяет разработчикам регистрировать на узлах DOM так называемых «слушателей событий» - event listeners. И хотя большинство событий вызываются действиями пользователя, существуют и такие, которые могут быть инициированы и без этого, - например, события по времени и асинхронные вызовы. При этом каждое событие может отдаваться эхом по всему дереву DOM и активировать сразу несколько «слушателей». Иногда отследить все это - довольно нетривиальная задача.

    Как обрабатываются события

    По этим причинам код на JS может быть труден для понимания, анализа и тестирования. Облегчат жизнь веб-разработчику и помогут писать безопасный код специальные утилиты.

    Утилиты для тестирования кода на JS

    Существуют утилиты для парсинга (например, Esprima , Rhino), оптимизации (например, Google Closure Compiler) и статического анализа кода на наличие распространенных синтаксических ошибок (например, JSHint).

    Кроме того, есть несколько проверенных фреймворков, которые помогают веб-разработчикам покрывать JS-код тестами. Среди них:

    • QUnit - популярный фреймворк для тестирования модулей;
    • Jasmine - BDD-фреймворк (Behavior-driven Development) для тестирования кода;
    • Mocha - фреймворк для тестирования кода, запускается как в Node.js, так и в браузере;
    • jsTestDriver - фреймворк, который в числе прочего может прогонять набор тестов сразу через несколько браузеров.

    Кроме того, существуют тестирующие фреймворки, которые эмулируют поведение браузера и позволяют автоматически прогонять тестовые примеры. Они особенно актуальны при отладке участков кода, которые отвечают за взаимодействие между JS и DOM, и предоставляют удобную инфраструктуру для манипулирования DOM.

    К примеру, Selenium , PhantomJS и SlimerJS предоставляют API, через который можно запускать экземпляры браузера и работать с ними. Через API ты можешь активировать события и получать доступ к элементам DOM прямо в рантайме - то есть тестировать код в условиях, максимально приближенных к реальным. Конечно, немалую часть работы придется проделывать вручную, но даже это уже неплохая помощь в тестировании.

    Утилиты для статического анализа

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

    WARI - статический анализатор, который исследует зависимости между функциями JS, стилями CSS, тегами HTML и изображениями. Смысл этой утилиты - находить при статическом анализе неиспользуемые ресурсы. Однако с динамикой WARI, конечно, не справится.

    JSLint - утилита для анализа статического кода, которая сама написана на JavaScript. Она проверяет код на соответствие хорошим практикам.

    Google Closure Compiler - JS-оптимизатор, который автоматически переписывает код с целью сделать его быстрее и компактнее. Заодно в трубу вылетают все комментарии и любые неиспользуемые участки кода.

    WebScent (см. научную работу) - продвинутый статический анализатор. В работе он исходит из того, что клиентский JS-код (тот, который загружается в браузер) не хранится на стороне сервера в целом виде, а рассеян по серверному коду кусками. «Душок» в этих кусках не может быть легко обнаружен до тех пор, пока из них не будет сгенерирован цельный клиентский код. WebScent анализирует клиентский код с тем, чтобы найти проблемные места в серверном коде. При этом работа статического анализатора WebScent в основном сводится к распутыванию замесов HTML, CSS и JS - с целью обнаружить дублирующийся код и ошибки в синтаксисе HTML.

    Утилиты для динамического анализа

    JSNose - утилита, в которой объединены статический и динамический анализ. Она анализирует код на наличие тринадцати антипаттернов. Семь из них (в том числе lazy object и long function) - общие для всех языков программирования, а шесть остальных (closure smells, excessive global variables, nested callbacks и другие) специфичны для JavaScript.

    DOMPletion - автоматизированная утилита, которая помогает веб-разработчику понимать код при просмотре: объясняет причину присутствия структур DOM, выполняет динамический анализ, а также предоставляет умный автокомплит для кода, который взаимодействует с DOM.

    Clematis - фреймворк, который помогает распутывать сложные событийные взаимодействия. Clematis детально фиксирует все события, которые срабатывают при выполнении, и визуализирует их в виде абстрактной поведенческой модели, в которой отражаются временные и причинно-следственные связи между компонентами и событиями.

    Выводы

    Итак, отследить происходящее при выполнении скриптов на JS бывает непросто, но, вооружившись подходящими инструментами, найти и переписать проблемные места можно даже в самом запутанном коде. Впрочем, JavaScript не стоит на месте: в нем появляются новые и новые возможности, теперь он часто используется для написания приложений (как мобильных, так и десктопных), а также все чаще встречается на серверах (и не только) благодаря Node.js. А это значит, что и искусство ловли багов нужно выводить на новый уровень.

    И преподаватель Нетологии, написал для блога цикл статей о EcmaScript6. В первой части на примерах рассмотрим динамический анализ кода в EcmaScript с помощью Iroh.js.

    Статический и динамический анализ кода

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

    Выводы

    Iroh.js — мощный и функциональный инструмент для динамического анализа кода в EcmaScript-е. Этот инструмент может быть использован как для анализа кода, включая построения графа вызовов, вывода актуальных типов и значений в переменных и объектах, так и для модификации кода на лету, включая исправления кода, основанные на событиях.

    Динамический анализ — довольно сложный метод, однако для EcmaScript, учитывая утиную типизацию, наличие host-объектов и нативных функций, позволяющих менять поведения кода на лету, это единственный способ для анализа и отладки кода в процессе выполнения. Iroh.js также может использовать для создания функциональных тестов код без необходимости его предварительной модификации для экспорта значений.

    Далеко не каждая строка моего кода получается идеальной с первого же раза. Ну, в некоторых случаях… Иногда… Ладно – практически никогда. Правда заключается в том, что я трачу значительно больше времени на исправление своих собственных глупых ошибок, чем мне хотелось бы. Именно поэтому я использую статические анализаторы практически в каждом написанном мной файле JavaScript.

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

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

    JSLint, JSHint и Closure Compiler

    Есть три основных варианта статических анализаторов для JavaScript: JSLint, JSHint и Closure Compiler.

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

    Var s = "mystring"; for (var i = 0; i < s.length; i++) { console.log(s.charAt(i)); }

    JSLint показывает в этом коде две ошибки:

    Unexpected "++". Move "var" declarations to the top of the function.

    Первая проблема – это определение переменной i в условиях цикла. JSLint также не принимает оператор ++ в конце определения цикла. Он хочет, чтобы код выглядел следующим образом:

    Var s = "mystring"; var i; for (i = 0; i < s.length; i = i + 1) { console.log(s.charAt(i)); }

    Я ценю создателей JSLint, но как по мне – это перебор. Он оказался жестким и для Антона Ковалева, поэтому он создал JSHint.

    JSHint работает так же, как и JSLint, но он написан в дополнение к Node.js, а потому он более гибкий. JSHint включает большое количество опций, что позволяет выполнять пользовательские проверки путем написания своего собственного генератора отчетов.
    Запустить JSHint можно с сайта , но в большинстве случаев лучше установить JSHint в качестве локального инструмента командной строки с помощью Node.js. Как только вы установите JSHint, его можно запустить в ваших файлах с помощью такой команды:

    Jshint test.js

    JSHint также включает плагины для популярных текстовых редакторов, поэтому его можно запускать в процессе написания кода.

    CLOSURE COMPILER

    Closure Compiler от Google – это совсем другая разновидность программы. Как предполагает его название, он представляет собой не только программу для проверки, но и компилятор. Он написан на Java и основан на анализаторе Rhino от Mozilla. Closure Compiler включает простой режим для выполнения базовой проверки кода, и более сложные режимы, позволяющие выполнять дополнительную проверку и обеспечивать соблюдение определений отдельных видов.

    Closure Compiler сообщает об ошибках в коде JavaScript, но также создает минимизированные версии JavaScript. Компилятор удаляет пустое пространство, комментарии и неиспользуемые переменные и упрощает длинные выражения, делая скрипт максимально компактным.

    Google сделал очень простую версию компилятора, доступную в сети , но скорее всего, вы захотите скачать Closure Compiler и запустить его локально.

    Closure Compiler после проверки кода выводит список файлов в один минимизированный файл. Таким образом, вы можете запустить его, скачав файл compiler.jar.

    Java -jar compiler.jar --js_output_file compress.js --js test1.js --js test2.js

    Выбираем правильную программу проверки

    В своих проектах я комбинирую Closure Compiler и JSHint. Closure Compiler выполняет минимизацию и базовую проверку, в то время как JSHint проводит более сложный анализ кода. Эти две программы отлично работают вместе, и каждая из них охватывает те области, которые не может охватить другая. Кроме того, я могу использовать возможности расширения JSHint, чтобы писать пользовательские программы проверки. Одна написанная мной общая программа проверяет определенные функции, которые мне не нужны, например вызов функций, которых не должно быть в моем проекте.

    Теперь, когда мы рассмотрели несколько программ для проверки, давайте разберем немного плохого кода. Каждый из этих шести примеров представляет собой код, который не стоит писать, и ситуации, в которых программы проверки кода могут спасти вас.

    В этой статье для большинства примеров используется JSHint, но Closure Compiler обычно выдает похожие предупреждения.

    == или ===?

    JavaScript – это язык с динамической типизацией. Вам не нужно определять типы в процессе написания кода, при этом они существуют при запуске.

    JavaScript предлагает два оператора сравнения для управления такими динамическими типами: == и ===. Давайте рассмотрим это на примере.

    Var n = 123; var s = "123"; if (n == s) { alert("Переменные равны"); } if (n === s) { alert("Переменные идентичны"); }

    Оператор сравнения == - это остатки языка С, в который JavaScript уходит корнями. Его использование практически всегда является ошибкой: сравнивание значений отдельно от типов редко является тем, что разработчик на самом деле хочет сделать. На самом деле, число «сто двадцать три» отличается от строки «один два три». Эти операторы легко неправильно написать и еще легче неправильно прочесть. Проверьте этот код с помощью JSHint и вы получите следующее:

    Test.js: line 9, col 12, Expected "===" and instead saw "==".

    Неопределенные переменные и поздние определения

    Давайте начнем с простого кода:

    Function test() { var myVar = "Hello, World"; console.log(myvar); }

    Видите баг? Я совершаю эту ошибку каждый раз. Запустите этот код, и вы получите ошибку:

    ReferenceError: myvar is not defined

    Давайте сделаем проблему немного более сложной:

    Function test() { myVar = "Hello, World"; console.log(myVar); }

    Запустите этот код, и вы получите следующее:

    Hello, World

    Этот второй пример работает, но у него есть очень неожиданные побочные действия. Правила для определения переменных JavaScript и области видимости оказываются, в лучшем случае, запутанными. В первом случае JSHint сообщит следующее:

    Test.js: line 3, col 17, "myvar" is not defined.

    Во втором случае он сообщит такое:

    Test.js: line 2, col 5, "myVar" is not defined. test.js: line 3, col 17, "myVar" is not defined.

    Первый пример поможет вам избежать ошибки времени выполнения программы. Вам не нужно тестировать свое приложение - JSHint найдет ошибку за вас. Второй пример хуже, так как в результате тестирования вы не найдете баг.

    Проблема второго примера коварно незаметная и сложная. Переменная myVar теперь исчезла из своей области видимости и поднялась в глобальную область. Это означает, что она будет существовать и иметь значение Hello, World даже после запуска функции test. Это называется «загрязнение глобальной области видимости».

    Переменная myVar будет существовать для каждой другой функции, которая будет запущена после функции test. Запустите следующий код после того, как выполните функцию test:

    Console.log("myVar: " + myVar);

    Вы все равно получите Hello, World. Переменная myVar будет висеть по всему вашему коду как шаблон, который приводит к сложным багам, которые вы будете искать всю ночь перед релизом, а все потому, что вы забыли вписать var.

    АЛЕКСАНДР МАЙОРОВ, программист, 11 лет занимается программированием, семь из которых посвятил разработке под мобильные устройства

    Статический анализ типов в JavaScript
    Пробуем анализатор Flow от Facebook

    Компания Facebook представила новый открытый проект Flow - статический анализатор кода для языка JavaScript. Основной целью разработки анализатора является упрощение поиска ошибок

    Дополнительно Flow предоставляет средства в виде синтаксического расширения языка JavaScript в стиле TypeScript для явного указания типов. Поддерживаются многие новые возможности, представленные в спецификации ECMAScript 6.

    Тема типизации в языках программирования затрагивается часто. Это предмет холиваров и определения положительной или отрицательной черты конкретного языка. В последнее время стали много говорить о типизации в JavaScript. Кому-то она нравится в том виде, как есть. Люди, знакомые с другими языками программирования, особенно со строгой явной типизацией, считают такой подход «гранатой в руках обезьяны». Все мы знаем, что JavaScript - это язык с нестрогой динамической типизацией. Гуру фронтенд-разработки научились использовать это во благо, но код порой тяжеловат для понимания. Те, кто только приходит в мир программирования на JavaScript, недоумевают от магии, которую делает интепретатор, и часто ловят ошибки «на ровном месте». Но давайте сначала немного разберемся в типизации вообще. Какая она бывает?

    Типизация в языках программирования

    Языки программирования по типизации делятся на два больших лагеря - типизированные и нетипизированные. К типизированным, например, относятся такие языки, как C, Python, PHP, Lua, JavaScript. Примеры нетипизированных языков: ассемблер, Forth, Brainfuck. Да-да, именно так. JavaScript, как и многие другие интерпретируемые языки, - типизированный. Поэтому ни в коем случае не говорите, что он нетипизированный. Особенно на собеседованиях.

    В свою очередь, типизированные языки разделяются еще на несколько пересекающихся категорий:

    • Со статической или динамической типизацией.
    • Со строгой или нестрогой типизацией.
    • С явной или неявной типизацией.

    Языки со статической типизацией

    При статической типизации конечные типы переменных и функций устанавливаются на этапе компиляции. Компилятор еще до запуска программы исправляет ваши ошибки при несоответствии типов. Примеры языков: C, Java, C#.

    Языки с динамической типизацией

    В динамической типизации все типы выясняются уже во время выполнения программы. И если вы допустили ошибку, то узнаете об этом только при выполнении программы. Поэтому при динамической типизации очень важно уделять особое внимание проверкам и перехвату ошибок. Примеры языков: JavaScript, PHP, Python, Ruby.

    Строгая типизация (сильная)

    Языки со строгой типизацией не позволяют смешивать в выражениях различные типы и не будут выполнять автоматические неявные преобразования типов. К примеру, нельзя вычесть из строки число или какой-то другой тип, отличный от строкового. Примеры языков: Java, Python, Haskell, Lisp.

    Нестрогая типизация (слабая)

    Языки с нестрогой типизацией выполняют множество неявных преобразований типов автоматически. Они делают это, даже если может произойти потеря точности или преобразование, неоднозначно. Примеры языков: PHP, JavaScript, Visual Basic.

    Явная типизация

    В явно типизированных языках тип новых переменных/функций и аргументов нужно задавать явно. Примеры языков: C++, D, C#.

    Неявная типизация

    В языках с неявной типизацией задачу по указанию типов перекладывают на компилятор/интерпретатор. Примеры языков: JavaScript, PHP, Lua. В таких языках, как правило, у объектов существуют специальные методы, вызываемые при приведении к типу. К примеру, в PHP есть метод _toString(), а в JavaScript одноименный метод, но без подчеркивания - toString(). Эти методы вызываются при приведении объекта к строковому типу. Иногда такие методы называют магическими (любые неявные процессы - это всегда магия).

    Важно заметить, что все эти категории пересекаются. Исходя из этих категорий, получаем, что JavaScript имеет динамическую неявную типизацию. А если говорить утрированно, то характер языка можно описать так: в любой непонятной ситуации приводи все к примитивам, преимущественно к строке. Хотя на деле все немного сложнее, но не будем сейчас вдаваться в подробности.

    «А зачем нам типизация?» - можете спросить вы. Без нее JavaScript хорошо жил на протяжении 20 лет. Ответ прост: раньше на JavaScript не решались сложные задачи корпоративного уровня. Сейчас этот язык вышел за пределы браузера и зашел на территорию бэкенда. При написании большого приложения становится сложно отлавливать ошибки, которые часто связаны именно с приведением типов.

    Надстройки на JavaScript

    Так как JavaScript выполняется на клиентской стороне (в браузерах), то одним из вариантов решения проблемы видится создание языка - диалекта, который будет компилироваться в JS. Он выступает в роли ассемблера.

    Появились такие языки, как TypeScript, Dart, AtScript, которые добавляют статическую строгую типизацию и даже проверку типов во время исполнения (хотя это добавляет накладные расходы). Все эти языки не просто добавляют типы, они также добавляют либо синтаксический сахар, либо вовсе свою реализацию VM, которая написана на JS.

    Статью целиком читайте в журнале «Системный администратор», №1-2 за 2015 г. на страницах 86-88.

    PDF-версию данного номера можно приобрести в нашем магазине .

    1. Сайт Flow - http://flowtype.org .

    Вконтакте