Видео со встречи: http://getdev.net/Event/javascript-good-form
Рассказ о том, как в приличном обществе принято структурировать свой JavaScript, разбивать его на отдельные логические единицы, инкапсулировать его от внешней среды, подключать скрипты к своему веб-приложению, и организовывать процесс юнит-тестирования и как заменять им компилятор
2. JavaScript
Самый популярный и самый ненавидимый язык
программирования в мире
▪ Первая инкарнация – под именем LiveScript (в девичестве Mocha)
▪ Переименован в JavaScript как знак союза двух корпораций
Этим переименованием были введены в заблуждение, и вводяся до сих пор,
многие и многие программисты
▪ Стандартизован под именем ECMAScript
▪ Синтаксисом напоминает Си-подобные языки и Java, чем и вызывает
большую часть ненависти в свой адрес, так как ведет себя иногда
совершенно по иному.
3. Где используется ECMAScript?
▪ Браузеры – клиентская часть веб-сайтов.
▪ NodeJS – серверная часть веб-сайтов
▪ Action Script (Flash, Flex)
▪ Шеллы для Windows/Linux
▪ Внедрение в собственные продукты для предоставления пользователям
возможностей программирования
▪ И даже попытки программировать микроконтроллеры
4. JavaScript как кривое зеркало Си-языков
▪ JavaScript особенно неприятен людям, которые долго и успешно писали на
Си-подобных языках
▪ Тут похожие циклы, похожие фигурные скобочки, чуть-чуть похожее
объявление фукций и переменных...
▪ И совсем другие области видимости и правила работы с необъявленными
переменными
5. Проверка и присвоение значений
Си-подобные JavaScript
▪ if (item != null) ▪ if (item)
▪ if (str != null && str.length > 0) ▪ if (str)
▪ if (val != 0) { x = val; } else { x = 5; } ▪ x = val || 5;
▪ if (item != null) { x = item.text; } ▪ x = item && item.text;
6. === и его злобный брат-близнец ==
▪ Все приходящие с Си-языков пишут: Выражение Результат
if(a == b) {
… 5 == “5” True
}
Оно даже как будто бы работает 0 == null False
▪ Но очень смешно – пытаясь undefined == null True
приводить типы и сравнивать „0‟ == „‟ False
результат.
0 == „0‟ True
▪ Лучше использовать пару === / !==,
которая не использует приведение 0 == „‟ True
типов
' trn ' == 0 True
▪ Тогда ни у кого из читателей кода не false == „0‟ True
возникнет вопрос, является ли
ошибкой равенство 0 == false, или
это ваш хитрый приѐм
программирования
7. Объявление переменных
▪ То, что нужно помнить всегда – областью видимости переменной является
функция
▪ Причем вся функция, а не только та часть функции, которая ниже
объявления переменной
8. Подъем переменых (variables hoisting)
Что пишем мы Как это читает JavaScript
function f() { function f() {
var greeting = ‘hello’; var greeting = ‘hello’,
for(var i = 0; i < 4; i++) i = undefined,
{ spaced = undefined;
var spaces = ‘ ‘ + ‘ ‘; for(i = 0; i < 4; i++)
greeting += spaces; {
} spaces = ‘ ‘ + ‘ ‘;
} greeting += spaces;
}
}
9. Простое правило – пишите так, как это
прочитает JavaScript
▪ Все переменные, используемые в функции, всегда объявляйте на самом еѐ
верху
▪ Во всей функции должен быть только один оператор var – на первой позиции
▪ Так вы сможете гарантировать отсутствие недопониманий со стороны менее
опытных разработчиков
▪ И – да, это коренным образом расходится с советом из Си – объявляйте
переменную по месту еѐ использования
И поначалу вызывает оторопь.
10. В сложных функциях появляются огромные
секции объявления переменных
function f() {
var i,
j,
k,
greeting = 'hello',
total = 0,
name = "GetDev.NET",
message = greeting + " " + name,
st,
containerId = '#container‘,
minX,
maxX,
minY,
maxY,
tempResult,
…..
Что служит неплохим сигналом к рефакторингу
11. Не засоряйте глобальный объект
▪ Каждая ваша новая переменная, созданная вне функции, добавляется к
глобальному объекту. Туда же (в обычном режиме) добавляют и
переменные, которые забыли объявить.
▪ С каждой новой переменной увеличивается риск совпадения имен – как
между вашими собственными переменными, так и между добавленными
сторонней библиотекой или плагином браузера/среды выполнения
▪ (Кстати, если вы используете переменную без объявления, причем в любом
месте, то она, обычно, попадает как раз в глобальный объект. Исключение –
“strict mode”)
12. Namespaces
▪ Вообще-то их в JavaScript нет, но, условно говоря, они есть
▪ В качестве namespace используется обычный объект – в идеале – один
корневой объект на приложение
▪ Все остальные переменные являются его свойствами
var GetDevNet = GetDevNet || {};
GetDevNet.map = new Map();
GetDevNet.url = ‚http://getdev.net/‛
▪ Смысле этого ровно тот же: логическая группировка объектов, функций и
переменных (теперь – свойств)
13. Самовызывающиеся функции
▪ Самовызывающаяся функция – функция, которая исполняется немедленно
после объявления
▪ Смысле еѐ – спрятать внутри себя логику, переменные и данные
(function (GD, $, global) {
GD.title = $(‚#title‛).text();
})(GetDevNet, jQuery, window);
14. Замыкания
▪ Хранение ссылок на объекты/значения из более высокого скопа
function getItemsCounter() {
var count = 0;
return {
getItemsCount: function () {
return count;
},
addItem: function () {
count++;
}
};
}
▪ Позволяет иметь приватные данные – счетчик здесь
15. Классы…
▪ Типичные стадии изучения JavaScript:
- узнаем язык программирования
- узнаем, что в JS есть классы!
- узнаем, что в объектах классов нет приватных свойств
- узнаем, что в JS нет классов. Есть функции-конструкторы
- узнаем, что в функциях-конструкторах можно организовать приватные
свойства
Но это тема отдельная и довольно глубокая.
17. Используйте Strict Mode
▪ “strict mode”;
▪ Старые браузеры эту строку проигнорируют, а новые переключатся на
использование строгого режима – подмножества разрешенных операций
JavaScript
▪ Тут вы уже не сможете случайно объявить глобальную переменную, что
плюс уже само по себе
18. Юнит-тестировние
▪ Юнит-тестирование – это хорошо в принципе
Но для JavaScript это хорошо особенно
▪ В отличие от компилируемых языков, в которых проверка синтаксиса всего кода
выполняется естественным образом во время компиляции, об ошибке
синтаксиса JavaScript мы узнаем только во время выполнения
▪ Автоматически запускаемые юнит-тесты помогают значительно приблизить во
времени момент выявления ошибки
▪ Вместо цикла «написал - откомпилировал – узнал об ошибке» получаем цикл
«написал – залился – запустились тесты на Continous Integration-сервере –
узнал об ошибке».
Что несколько дольше во времени, но все равно быстрее и надежнее, чем
«написал – выложил – получил сообщение от пользователей «что-то не
работает»»
19. Существующие фреймворки
▪ QUnit – от автором jQuery, написанный для тестирования jQuery
Просто нормальный фреймворк
Набор ассертов, setup/teardown, визуальный интерфейс как HTML-страница
Выполняется внутри браузера (просто открываем HTML-файл с тестами)
Отсутствует возможность запуска на сервере вне браузера
▪ JUnit JS – тот же шарик, вид сбоку
assertEqual-операции принимают аргументы в порядке, обратном QUnit, так
что заменить в процессе один на другой будет более проблематично
▪ Jasmine – Behavior Driven Development фреймворк
Из плюсов – улучшенная поддержка Mock- и Spy-объектов из коробки
▪ PhantomJS – среда для запуска JavaScript-тестов без браузера
20. Организация Continous Integration
▪ Первый подход – запускать на сервере браузер и прогонять в нѐм тесты
▪ Второй подход – запускать на сервере тесты в невизуальной среде
(PhantomJS, V8)
▪ Оба подхода имеют преимущества и недостатки
22. Интересное чтение
▪ JavaScript: the Good Parts by Douglas Crockford
▪ http://javascript.ru
▪ StackOverflow – unit testing discussion
23. Интересное видео
▪ The Tale of JavaScript. I Mean ECMAScript. by Douglas Crockford
▪ Good JavaScript Habits for C# Developers by Elijah Manor
▪ Structuring JavaScript Code – Pluralsight
▪ Crockford on JavaScript video series on Yahoo!
24. Интересные ссылки
▪ JSLint - средство поиска очевидных ошибок и проверка следованию
хорошему стилю программирования
http://www.jslint.com/
▪ JS Fiddle – средство исполнения кода, разметки и CSS-стилей в онлайне
http://jsfiddle.net/
▪ QUnit
http://qunit.org
▪ PhantomJS
http://phantomjs.org/
25. Вопросы?
Внимательно слушаю!
Андрей Кулешов
kaa-tula@ya.ru
akuleshov.tula
Специально для http://GetDev.NET