Post on 24-Jan-2015
description
JavaScriptХороший тон клиентской разработки
Андрей Кулешов
JavaScriptСамый популярный и самый ненавидимый язык программирования в мире
▪ Первая инкарнация – под именем LiveScript (в девичестве Mocha)
▪ Переименован в JavaScript как знак союза двух корпорацийЭтим переименованием были введены в заблуждение, и вводяся до сих пор, многие и многие программисты
▪ Стандартизован под именем ECMAScript
▪ Синтаксисом напоминает Си-подобные языки и Java, чем и вызывает большую часть ненависти в свой адрес, так как ведет себя иногда совершенно по иному.
Где используется ECMAScript?
▪ Браузеры – клиентская часть веб-сайтов.
▪ NodeJS – серверная часть веб-сайтов
▪ Action Script (Flash, Flex)
▪ Шеллы для Windows/Linux
▪ Внедрение в собственные продукты для предоставления пользователям возможностей программирования
▪ И даже попытки программировать микроконтроллеры
JavaScript как кривое зеркало Си-языков
▪ JavaScript особенно неприятен людям, которые долго и успешно писали на Си-подобных языках
▪ Тут похожие циклы, похожие фигурные скобочки, чуть-чуть похожее объявление фукций и переменных...
▪ И совсем другие области видимости и правила работы с необъявленными переменными
Проверка и присвоение значений
Си-подобные
▪ if (item != null)
▪ if (str != null && str.length > 0)
▪ if (val != 0) { x = val; } else { x = 5; }
▪ if (item != null) { x = item.text; }
JavaScript
▪ if (item)
▪ if (str)
▪ x = val || 5;
▪ x = item && item.text;
=== и его злобный брат-близнец ==
▪ Все приходящие с Си-языков пишут:if(a == b) { …}Оно даже как будто бы работает
▪ Но очень смешно – пытаясь приводить типы и сравнивать результат.
▪ Лучше использовать пару === / !==, которая не использует приведение типов
▪ Тогда ни у кого из читателей кода не возникнет вопрос, является ли ошибкой равенство 0 == false, или это ваш хитрый приём программирования
Выражение Результат
5 == “5” True
0 == null False
undefined == null
True
‘0’ == ‘’ False
0 == ‘0’ True
0 == ‘’ True
' \t\r\n ' == 0 True
false == ‘0’ True
Объявление переменных
▪ То, что нужно помнить всегда – областью видимости переменной является функция
▪ Причем вся функция, а не только та часть функции, которая ниже объявления переменной
Подъем переменых (variables hoisting)
Что пишем мы
function f() { var greeting = ‘hello’; for(var i = 0; i < 4; i++) { var spaces = ‘ ‘ + ‘ ‘; greeting += spaces; }}
Как это читает JavaScript
function f() { var greeting = ‘hello’, i = undefined, spaced = undefined; for(i = 0; i < 4; i++) { spaces = ‘ ‘ + ‘ ‘; greeting += spaces; }}
Простое правило – пишите так, как это прочитает JavaScript
▪ Все переменные, используемые в функции, всегда объявляйте на самом её верху
▪ Во всей функции должен быть только один оператор var – на первой позиции
▪ Так вы сможете гарантировать отсутствие недопониманий со стороны менее опытных разработчиков
▪ И – да, это коренным образом расходится с советом из Си – объявляйте переменную по месту её использованияИ поначалу вызывает оторопь.
В сложных функциях появляются огромные секции объявления переменных
function f() {var i, j, k, greeting = 'hello', total = 0, name = "GetDev.NET", message = greeting + " " + name, st, containerId = '#container‘, minX, maxX, minY, maxY, tempResult,…..
Что служит неплохим сигналом к рефакторингу
Не засоряйте глобальный объект
▪ Каждая ваша новая переменная, созданная вне функции, добавляется к глобальному объекту. Туда же (в обычном режиме) добавляют и переменные, которые забыли объявить.
▪ С каждой новой переменной увеличивается риск совпадения имен – как между вашими собственными переменными, так и между добавленными сторонней библиотекой или плагином браузера/среды выполнения
▪ (Кстати, если вы используете переменную без объявления, причем в любом месте, то она, обычно, попадает как раз в глобальный объект. Исключение – “strict mode”)
Namespaces
▪ Вообще-то их в JavaScript нет, но, условно говоря, они есть
▪ В качестве namespace используется обычный объект – в идеале – один корневой объект на приложение
▪ Все остальные переменные являются его свойствами
var GetDevNet = GetDevNet || {};GetDevNet.map = new Map();GetDevNet.url = “http://getdev.net/”
▪ Смысле этого ровно тот же: логическая группировка объектов, функций и переменных (теперь – свойств)
Самовызывающиеся функции
▪ Самовызывающаяся функция – функция, которая исполняется немедленно после объявления
▪ Смысле её – спрятать внутри себя логику, переменные и данные
(function (GD, $, global) { GD.title = $(“#title”).text();})(GetDevNet, jQuery, window);
Замыкания
▪ Хранение ссылок на объекты/значения из более высокого скопаfunction getItemsCounter() { var count = 0; return { getItemsCount: function () { return count; }, addItem: function () { count++; } };}
▪ Позволяет иметь приватные данные – счетчик здесь
Классы…
▪ Типичные стадии изучения JavaScript:- узнаем язык программирования- узнаем, что в JS есть классы!- узнаем, что в объектах классов нет приватных свойств- узнаем, что в JS нет классов. Есть функции-конструкторы- узнаем, что в функциях-конструкторах можно организовать приватные свойства
Но это тема отдельная и довольно глубокая.
Модули
▪ Задача модуля – инкапсуляция независимого куска логики
▪ var GetDevModule = (function ($, global) { //some initialization… … var module = { … … } ; return module;})(jQuery, window);
▪ (function (GetDev, $, global) { GetDev.module = { … … };})(GetDev, jQuery, window);
Используйте Strict Mode
▪ “strict mode”;
▪ Старые браузеры эту строку проигнорируют, а новые переключатся на использование строгого режима – подмножества разрешенных операций JavaScript
▪ Тут вы уже не сможете случайно объявить глобальную переменную, что плюс уже само по себе
Юнит-тестировние
▪ Юнит-тестирование – это хорошо в принципеНо для JavaScript это хорошо особенно
▪ В отличие от компилируемых языков, в которых проверка синтаксиса всего кода выполняется естественным образом во время компиляции, об ошибке синтаксиса JavaScript мы узнаем только во время выполнения
▪ Автоматически запускаемые юнит-тесты помогают значительно приблизить во времени момент выявления ошибки
▪ Вместо цикла «написал - откомпилировал – узнал об ошибке» получаем цикл «написал – залился – запустились тесты на Continous Integration-сервере – узнал об ошибке».Что несколько дольше во времени, но все равно быстрее и надежнее, чем «написал – выложил – получил сообщение от пользователей «что-то не работает»»
Существующие фреймворки
▪ QUnit – от автором jQuery, написанный для тестирования jQueryПросто нормальный фреймворкНабор ассертов, setup/teardown, визуальный интерфейс как HTML-страницаВыполняется внутри браузера (просто открываем HTML-файл с тестами)Отсутствует возможность запуска на сервере вне браузера
▪ JUnit JS – тот же шарик, вид сбокуassertEqual-операции принимают аргументы в порядке, обратном QUnit, так что заменить в процессе один на другой будет более проблематично
▪ Jasmine – Behavior Driven Development фреймворкИз плюсов – улучшенная поддержка Mock- и Spy-объектов из коробки
▪ PhantomJS – среда для запуска JavaScript-тестов без браузера
Организация Continous Integration
▪ Первый подход – запускать на сервере браузер и прогонять в нём тесты
▪ Второй подход – запускать на сервере тесты в невизуальной среде (PhantomJS, V8)
▪ Оба подхода имеют преимущества и недостатки
Демо – создание страницы с тестами
Интересное чтение
▪ JavaScript: the Good Parts by Douglas Crockford
▪ http://javascript.ru
▪ StackOverflow – unit testing discussion
Интересное видео
▪ 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!
Интересные ссылки
▪ JSLint - средство поиска очевидных ошибок и проверка следованию хорошему стилю программированияhttp://www.jslint.com/
▪ JS Fiddle – средство исполнения кода, разметки и CSS-стилей в онлайнеhttp://jsfiddle.net/
▪ QUnithttp://qunit.org
▪ PhantomJShttp://phantomjs.org/
Вопросы?Внимательно слушаю!
Андрей Кулешов
kaa-tula@ya.ru
akuleshov.tula
Специально для http://GetDev.NET