Написание лекции о современных
Однако если просмотреть встречающийся в сети код различных разработчиков Web, то можно прийти к выводу, что здравый смысл в действительности достаточно редок в используемом коде Web, и "создание разумных и логичных вещей" отодвигается далеко вниз в списке приоритетов, когда вы находитесь в середине проекта, и впереди смутно вырисовываются сроки окончания.
Поэтому данная лекция является компиляцией современных
Я уверен, что вы найдете здесь вещи, с которыми не согласны, и это хорошо - необходимо критично относиться к тому, что читаешь, и стараться найти лучшие решения. Однако, я обнаружил, что следование этим принципам сделало меня более эффективным разработчиком и позволило другим разработчикам с меньшими усилиями использовать мои разработки.
Лекция имеет следующую структуру:
Это не требует большого ума, но ужасно, как часто можно встретить в JavaScript переменные вида x1, fe2 или xbqne - или на другом конце спектра - с именами переменных типа incrementorForMainLoopWhichSpansFromTenToTwenty или createNewMemberIfAgeOverTwentyOneAndMoonIsFull.
Ни то, ни другое не имеет большого смысла - хорошие имена переменных и функций должны легко пониматься и говорить, что происходит - ни больше и ни меньше. Одной из ловушек, которой надо избежать, будет соединение значений и функций в именах. Функция с именем isLegalDrinkingAge() [ДопустимыйВозрастПьянства()] имеет больше смысла, чем isOverEighteen() [СтаршеВосемнадцати()], так как допустимый возраст принятия алкоголя меняется в различных странах, и существуют другие вещи, кроме принятия алкоголя, которые могут быть ограничены по возрасту.
Венгерская нотация является хорошей схемой
Например, если имеется переменная с именем familyName, и предполагается, что это будет строка, необходимо писать в венгерской нотации sFamilyName. Объект с именем member будет oMember, а булева переменная с именем isLegal будет bIsLegal. Это очень информативно для некоторых разработчиков, но для других кажется избыточным - каждый может решить самостоятельно, использовать это или нет.
Также хорошей идеей будет использование английского языка. Языки программирования базируются на английском языке, поэтому логично будет сохранить это и для всего остального кода. Поработав некоторое время над отладкой корейского и словенского кода, я могу утверждать, что это крайне трудная задача для иностранца.
Рассматривайте свой код как повествование. Если можно читать код строка за строкой и понимать, что происходит, то все отлично. Если приходится использовать блокнот, чтобы следить за логической последовательностью, то код требует некоторой переработки. Старайтесь быть проще.
Глобальные имена переменных и функций являются чрезвычайно плохой идеей. Причина в том, что каждый включенный в страницу файл JavaScript выполняется в одной и той же области действия. Если в коде имеются глобальные переменные или функции, то сценарии, включенные после ваших, и содержащие такие же имена переменных и функций, будут перезаписывать ваши переменные/функции.
Существует несколько подходов, позволяющие избежать использования глобальных переменных - мы рассмотрим их по очереди. Пусть имеются три функции и переменные:
var current = null;
function init(){...}
function change(){...}
function verify(){...}
Можно защитить это от перезаписи, используя литерал объекта:
var myNameSpace = {
current:null,
init:function(){...},
change:function(){...},
verify:function(){...}
}
Это помогает решить проблему, но имеется недостаток - чтобы вызывать функции или изменить значение переменной, всегда требуется использовать имя основного объекта: init() будет myNameSpace.init(), current будет myNameSpace.current, и т.д. Это может несколько надоедать.
Легче поместить все в анонимную функцию и защитить область действия таким образом. Это также означает, что не требуется изменять синтаксис с function name() на name:function(). Этот прием называется шаблон модуля (Module Pattern):
myNameSpace = function(){
var current = null;
function init(){...}
function change(){...}
function verify(){...}
}();
Этот подход тоже не без недостатков. Ничего из этого больше не будет доступно извне вообще. Если требуется сделать их доступными, необходимо использовать оператор return для элементов, которые надо сделать публично доступными:
myNameSpace = function(){
var current = null;
function verify(){...}
return{
init:function(){...}
change:function(){...}
}
}();
Это в значительной степени возвращает нас к исходной точке в смысле ссылок от одного к другому и изменения синтаксиса. Я поэтому предпочитаю делать что-то вроде следующего (и называю "раскрытие шаблона модуля"):
myNameSpace = function(){
var current = null;
function init(){...}
function change(){...}
function verify(){...}
return{
init:init,
change:change
}
}();
Вместо возвращения свойств и myNameSpace.
Это означает также, что можно иметь публичный
myNameSpace = function(){
var current = null;
function init(){...}
function change(){...}
function verify(){...}
return{
init:init,
set:change
}
}();
Вызов myNameSpace.set() будет вызывать теперь change().
Если не требуется, чтобы какие-либо переменные или функции были доступны извне, поместите просто всю конструкцию в другие скобки, чтобы выполнить ее, не присваивая никакого имени:
(function(){
var current = null;
function init(){...}
function change(){...}
function verify(){...}
})();
Это сохраняет все в аккуратном небольшом пакете, который недоступен для внешнего мира, но очень удобен для использования переменных и функций внутри.
Браузеры многое прощают, когда речь идет о синтаксисе JavaScript. Это не должно, однако, быть причиной для написания неряшливого кода, который полагается на браузеры, чтобы выполнить свою работу.
Проще всего проверить синтаксическое качество кода можно, пропуская его через ) - инструмент
JSLint может быть немного придирчив в отношении возвращаемых результатов - и его разработчик Дуглас Крокфорд говорит - он может оскорбить ваши чувства. Я обнаружил, однако, что стал писать код значительно лучше, с тех пор как установил пакет TextMate JS и начал подвергать код проверке JSLint.
Понятный и правильный код означает меньшее количество запутанных ошибок для исправления, облегчает передачу кода другим разработчикам, и улучшение
Правильный код означает также, что его можно преобразовать с помощью сценариев в другие форматы - хакерский код потребует для этого человека.
Комментарии являются сообщениями для других разработчиков (и себе самому, если придется вернуться к коду через какое-то время после работы над чем-то другим). За годы существования программирования неоднократно разгорались битвы, посвященные необходимости вообще использовать комментарии, основной аргумент при этом состоит в том, что хороший код должен объяснять себя сам.
Изъян такой позиции состоит в том, что объяснения являются крайне субъективной вещью - невозможно ожидать, что каждый разработчик понимает, что делает некоторый код, исходя из одних и тех же объяснений.
Комментарии никому не мешают, если они сделаны правильно. Мы вернемся к этому вопросу в конце этой лекции, но давайте скажем, что если комментарии отсутствуют в коде, который видят конечные пользователи, то что-то происходит неправильно.
Снова все определяет умеренность. Комментируйте, когда надо сказать что-то важное, и если комментируете, используйте нотацию /* */. Комментарии на одной строке, использующие //, могут создавать проблемы, если будет выполняться уменьшение объема кода без удаления комментариев, и, как правило, менее удобно.
Если комментарии используются для скрытия части кода, который будет использоваться позже или для отладки кода, существует удобный прием, который можно использовать:
module = function(){
var current = null;
function init(){
};
/*
function show(){
current = 1;
};
function hide(){
show();
};
*/
return{init:init,show:show,current:current}
}();
Добавление двойной косой черты перед закрывающей косой чертой со звездочкой позволяет комментировать и снимать комментарий для всего блока, просто удаляя или добавляя косую черту перед косой чертой и звездочкой, открывающими комментарий.
module = function(){
var current = null;
function init(){
};
/*
function show(){
current = 1;
};
function hide(){
show();
};
// */
return{init:init,show:show,current:current}
}();
Когда код задан так, как показано в блоке выше, добавление косой черты перед открывающей парой косой черты и звездочки превращает мультистрочный комментарий в два однострочных комментария, "открывая" код между ними и позволяя тем самым его выполнить. Удаление косой черты снова закомментирует блок.
Для более крупных приложений комментированная документация в стиле ) имеет большой смысл - общая документация продукта создается по мере написания кода. Успех библиотеки Yahoo
Хотя и возможно создать все необходимое в документе с помощью JavaScript и DOM, это не обязательно самый эффективный способ работы. Следующий код создает красную границу вокруг каждого поля ввода, когда его класс будет ", и в этом нет ничего сложного.
var f = document.getElementById('mainform');
var inputs = f.getElementsByTagName('input');
for(var i=0,j=inputs.length;i<j;i++){
if(inputs[i].className === 'mandatory'
inputs[i].value === ''){
inputs[i].style.borderColor = '#f00';
inputs[i].style.borderStyle = 'solid';
inputs[i].style.borderWidth = '1px';
}
}
Это работает, однако означает, что если в последующем потребуется изменить эти стили, придется просматривать код JavaScript и вносить в него изменения. Чем сложнее изменение, тем труднее будет выполнить редактирование. Более того, не каждый разработчик на JavaScript достаточно опытен или интересуется CSS, что означает много дополнительной работы, пока будет получен требуемый результат. Добавляя класс с именем "error" в элемент, когда имеется ошибка, можно гарантировать, что данные стиля будут храниться в CSS, что будет более подходящим:
var f = document.getElementById('mainform');
var inputs = f.getElementsByTagName('input');
for(var i=0,j=inputs.length;i<j;i++){
if(inputs[i].className === 'mandatory'
inputs[i].value === ''){
inputs[i].className += ' error';
}
}
Это значительно более эффективно, так как CSS предназначен для каскадного (иерархического) применения в документе. Пусть, например, желательно скрыть в документе все DIV с определенным классом. Можно в цикле просмотреть все DIV, проверить их классы, и затем изменить их совокупность стилей. В новых браузерах можно использовать процессор селекторов CSS, а затем изменить совокупность стилей. Проще всего, однако, использовать JavaScript для задания класса на элементе-предке и использовать в CSS синтаксис вдоль строк element.triggerclass div.selectorclass{}. Оставьте работу реального сокрытия DIV дизайнеру CSS, так как он лучше знает, как это сделать.
Сокращенная нотация является сложной темой: с одной стороны она сохраняет код небольшим, но с другой может создавать трудности для последующих разработчиков, так как они могут не знать о сокращениях. Вот небольшой список, что можно (и нужно) сделать.
Объекты являются, вероятно, наиболее универсальной вещью, имеющейся в JavaScript. Старая школа записывала их примерно следующим образом:
var cow = new Object();
cow.colour = 'brown';
cow.commonQuestion = 'What now?';
cow.moo = function(){
console.log('moo');
}
cow.feet = 4;
cow.accordingToLarson = 'will take over the world';
Однако это означает, что необходимо повторять имя объекта для каждого свойства или
var cow = {
colour:'brown',
commonQuestion:'What now?',
moo:function(){
console.log('moo');
},
feet:4,
accordingToLarson:'will take over the world'
};
Массивы являются в JavaScript несколько путаной темой. Можно найти множество сценариев, определяющих массив ( Array ) следующим образом:
var aweSomeBands = new Array(); aweSomeBands[0] = 'Bad Religion'; aweSomeBands[1] = 'Dropkick Murphys'; aweSomeBands[2] = 'Flogging Molly'; aweSomeBands[3] = 'Red Hot Chili Peppers'; aweSomeBands[4] = 'Pornophonique';
Здесь присутствует много бесполезного повторения. Все это можно переписать значительно быстрее, используя для массива сокращение [ ]:
var aweSomeBands = [ 'Bad Religion', 'Dropkick Murphys', 'Flogging Molly', 'Red Hot Chili Peppers', 'Pornophonique' ];
В некоторых руководствах может встретиться термин "ассоциативный массив". Это неправильное название, так как массивы с именованными свойствами, а не с индексом, являются в действительности объектами, и должны так определяться.
Условия можно сократить, используя "троичную запись". Например, следующая конструкция определяет переменную как 1 или -1, в зависимости от значения другой переменной:
var direction;
if(x > 100){
direction = 1;
} else {
direction = -1;
}
Это можно сократить до одной строки:
var direction = (x > 100) ? 1 : -1;
Все до знака вопроса является условием, значение сразу после него предназначено для истинного значения условия, а значение после двоеточия для ложного значения условия. Троичная запись может быть вложенной, но я бы избегал этого, чтобы сохранить
Другая распространенная ситуация в JavaScript состоит в задании предварительно заданного значения для переменной, если оно не определено, как в следующем случае:
if(v){
var x = v;
} else {
var x = 10;
}
В качестве сокращенной записи для этого случая используют две вертикальные черты:
var x = v || 10;
Это выражение автоматически задает для x значение 10, если v не определено - вот и все.
Это обычная практика программирования -
Это также применимо к созданию вспомогательных функций для общих задач. Если вы обнаружите, что делаете одно и то же в нескольких различных функциях, то лучше всего создать более общую
Один вход и один выход также имеют больше смысла, чем ветвление кода в самой функции. Предположим, необходимо написать
function addLink(text,url,parentElement){
var newLink = document.createElement('a');
newLink.setAttribute('href',url);
newLink.appendChild(document.createTextNode(text));
parentElement.appendChild(newLink);
}
Это работает нормально, но вам может понадобиться добавлять различные атрибуты, в зависимости от элементов, к которым применяется ссылка. Например:
function addLink(text,url,parentElement){
var newLink = document.createElement('a');
newLink.setAttribute('href',url);
newLink.appendChild(document.createTextNode(text));
if(parentElement.id === 'menu'){
newLink.className = 'menu-item';
}
if(url.indexOf('mailto:')!==-1){
newLink.className = 'mail';
}
parentElement.appendChild(newLink);
}
Это делает функцию более специфической, которую труднее применять в различных ситуациях. Более аккуратный способ состоит в возвращении ссылки и реализации дополнительных случаев в основных функциях, которые этого требуют. Это превращает addLink() в более общую функцию createLink():
function createLink(text,url){
var newLink = document.createElement('a');
newLink.setAttribute('href',url);
newLink.appendChild(document.createTextNode(text));
return newLink;
}
function createMenu(){
var menu = document.getElementById('menu');
var items = [
{t:'Home',u:'index.html'},
{t:'Sales',u:'sales.html'},
{t:'Contact',u:'contact.html'}
];
for(var i=0;i<items.length;i++){
var item = createLink(items[i].t,items[i].u);
item.className = 'menu-item';
menu.appendChild(item);
}
}
Когда каждая функция выполняет только одну специфическую задачу, можно иметь для приложения основную функцию init(), которая содержит всю структуру приложения. В этом случае можно легко изменять приложение и удалять функции, не просматривая остальной документ в поисках зависимостей.
Прогрессивное улучшение является практикой разработки, которая подробно рассматривается в лекции 13, Постепенное ухудшение или прогрессивное улучшение. По сути, вы должны написать код, который работает, независимо от доступной технологии. В случае JavaScript это означает, что когда создание сценария невозможно (скажем на BlackBerry, или в связи с крайне строгой политикой
Удивительно, как часто создаются крайне путаные приложения JavaScript для проблем, которые могут быть легко решены без этого. Один из примеров, который мне встречался, был полем поиска на странице, которое позволяло искать различные данные: web, изображения, новости, и т.д.
В исходной версии различные варианты данных были ссылками, которые должны были перезаписывать атрибут действия формы, чтобы указывать на различные сценарии на сервере для выполнения поиска.
Проблема в том, что если JavaScript будет отключен, ссылки все равно выводятся, но каждый вид поиска будет возвращать стандартные результаты из web, так как действие формы не изменяется. Решение было очень простым: вместо ссылок варианты были представлены как группа радио-кнопок, которые делали ветвление к различным сценариям специализированного поиска, используя серверный сценарий.
Это не только заставило поиск работать правильно для каждого варианта, но также облегчило отслеживание, сколько пользователей выбирает тот или иной вариант. Используя правильную конструкцию HTML, мы смогли избавиться, как от JavaScript для переключения действия формы, так и сценариев отслеживания переходов, и заставили ее работать для каждого пользователя - независимо от рабочей среды.
Одним из наиболее полезных действий для поддержания кода обслуживаемым и понятным является создание конфигурационного объекта, который содержит все вещи, которые возможно изменяются со временем. Сюда входит любой текст, используемый в создаваемых элементах (включая значения кнопок и
Например, плеер
/*
Это конфигурация плеера. Скорее всего вам никогда
не придется ничего здесь изменять, но иметь такую
возможность неплохо, не так ли?
*/
config = {
CSS:{
/*
Используемые в документе IDs. Сценарий будет получать
доступ к различным элементам плеера с помощью этих IDs,
поэтому, если вы изменяете их в коде HTML ниже,
не забудьте также изменить имена здесь!
*/
IDs:{
container:'eytp-maincontainer',
canvas:'eytp-playercanvas',
player:'eytp-player',
controls:'eytp-controls',
volumeField:'eytp-volume',
volumeBar:'eytp-volumebar',
playerForm:'eytp-playerform',
urlField:'eytp-url',
sizeControl:'eytp-sizecontrol',
searchField:'eytp-searchfield',
searchForm:'eytp-search',
searchOutput:'eytp-searchoutput'
/*
Отметим, что после последней записи в списке
никогда не должна стоять запятая, так как
иначе MSIE будет очень сердит!
*/
},
/*
Это имена классов CSS, которые плеер добавляет
динамически на панель громкости в определенных ситуациях.
*/
classes:{
maxvolume:'maxed',
disabled:'disabled'
/*
Отметим, что после последней записи в списке
никогда не должна стоять запятая, так как
иначе MSIE будет очень сердит!
*/
}
},
/*
Это конец определений CSS, отсюда и дальше вы можете
изменять настройки плеера самостоятельно.
*/
application:{
/*
Базовый URL API YouTube. Он изменился во время
разработки этого приложения, поэтому будет полезно
сделать его параметром.
*/
youtubeAPI:'http://gdata.youtube.com/apiplayer/cl.swf',
/*
Ключ YouTube Developer,
Замените его своим собственным, когда разместите
плеер на сервере!!!!!
*/
devkey:'AI39si7d...Y9fu_cQ',
/*
Увеличение/уменьшение громкости в процентах и сообщение
о громкости, выводимое в скрытом поле формы (для
считывателя экрана). $x в сообщении будет заменяться
реальным значением.
*/
volumeChange:10,
volumeMessage:'volume $x percent',
/*
Количество результатов поиска и сообщение об ошибке,
если результатов не будет.
*/
searchResults:6,
loadingMessage:'Searching, please wait',
noVideosFoundMessage:'No videos found : (',
/*
Количество секунд повторения, когда пользователь
нажимает кнопку обратной перемотки.
*/
secondsToRepeat:10,
/*
Размер кадра фильма.
*/
movieWidth:400,
movieHeight:300
/*
Отметим, что после последней записи в списке
никогда не должна стоять запятая, так как
иначе MSIE будет очень сердит!
*/
}
}
Если вы используете это как часть шаблона модуля и делаете его публичным, вы позволяете разработчику только переопределить, что ему требуется, перед инициализацией модуля.
Крайне важно поддерживать обслуживание кода простым, исключая для будущего персонала сопровождения необходимость чтения всего кода и поиска, где необходимо что-то изменить. Если это не очевидно, то решение будет либо полностью выброшено, либо грубо модифицировано. Модифицированные решения невозможно обновить, если в этом возникнет необходимость, тем самым уничтожается возможность повторного использования кода.
Вложенный код объясняет свою логику и облегчает чтение, однако вложение его слишком глубоко может также помешать проследить, что вы пытаетесь сделать. Читатели кода не должны использовать горизонтальную прокрутку, или страдать от путаницы, когда
Другой проблемой с вложением являются имена переменных и циклы. Вы обычно начинаете первый цикл с переменной i, и продолжаете, используя j, k, l и т.д. Это очень быстро может создать большую путаницу:
function renderProfiles(o){
var out = document.getElementById('profiles');
for(var i=0;i<o.members.length;i++){
var ul = document.createElement('ul');
var li = document.createElement('li');
li.appendChild(document.createTextNode(o.members[i].name));
var nestedul = document.createElement('ul');
for(var j=0;j<o.members[i].data.length;j++){
var datali = document.createElement('li');
datali.appendChild(
document.createTextNode(
o.members[i].data[j].label + ' ' +
o.members[i].data[j].value
)
);
nestedul.appendChild(datali);
}
li.appendChild(nestedul);
}
out.appendChild(ul);
}
Так как я использую здесь общие - в действительности выбрасываемые - имена переменных ul и li, мне нужны переменные nestedul и datali для вложенных элементов списка. Если вложение списка должно продолжаться еще глубже, понадобятся дополнительные имена переменных, и т.д. и т.д. Больше смысла имеет размещение задачи создания вложенных списков для каждого члена в свою собственную функцию, и вызов ее с правильными данными. Это также избавляет от цикла внутри цикла. Функция addMemberData() является достаточно общей и, скорее всего, может понадобиться и в других местах. С учетом этих соображений я переписал код следующим образом:
function renderProfiles(o){
var out = document.getElementById('profiles');
for(var i=0;i<o.members.length;i++){
var ul = document.createElement('ul');
var li = document.createElement('li');
li.appendChild(document.createTextNode(data.members[i].name));
li.appendChild(addMemberData(o.members[i]));
}
out.appendChild(ul);
}
function addMemberData(member){
var ul = document.createElement('ul');
for(var i=0;i<member.data.length;i++){
var li = document.createElement('li');
li.appendChild(
document.createTextNode(
member.data[i].label + ' ' +
member.data[i].value
)
);
}
ul.appendChild(li);
return ul;
}
Циклы могут стать очень медленными, если написать их неправильно. Одной из наиболее распространенных ошибок является чтение атрибута длины массива на каждой итерации:
var names = ['George','Ringo','Paul','John'];
for(var i=0;i<names.length;i++){
doSomeThingWith(names[i]);
}
Это означает, что каждый раз при выполнении цикла JavaScript необходимо прочитать длину массива. Можно избежать этого, сохраняя значение длины в другой переменной:
var names = ['George','Ringo','Paul','John'];
var all = names.length;
for(var i=0;i<all;i++){
doSomeThingWith(names[i]);
}
Еще короче это можно сделать, создавая вторую переменную в предварительном
var names = ['George','Ringo','Paul','John'];
for(var i=0,j=names.length;i<j;i++){
doSomeThingWith(names[i]);
}
Еще необходимо постараться сохранить код с большим объемом вычислений вне цикла. Сюда входят регулярные выражения и - более важно - манипуляции с DOM. Можно создавать узлы DOM в цикле, но старайтесь избегать вставлять их в документ. Дополнительно работа с DOM будет рассмотрена в следующем разделе.
Доступ к DOM в браузерах выполняется с большой нагрузкой. DOM является очень сложным API, и отображение в браузерах может требовать много времени. Это можно видеть при выполнении сложных Web-приложений, когда компьютер уже перегружен другой работой - изменения выполняются дольше или выводятся частично и т.д.
Чтобы гарантировать, что код работает быстро и не замедляет браузер до полной остановки, старайтесь поддерживать доступ к DOM на самом минимуме. Вместо непрерывного создания и применения элементов, используйте инструментальную функцию, которая превращает строку в элементы DOM, и вызывайте эту функцию в конце процесса генерации, чтобы вмешиваться в отображение браузера один раз, а не постоянно.
Создание кода, специально для определенного браузера, является надежным способом сделать код трудным для сопровождения, при этом код устареет достаточно быстро. Если посмотреть Web, можно найти множество сценариев, которые ожидают определенный браузер, и перестают работать, как только появляется новая версия или другой браузер.
Это пустая трата времени и усилий - необходимо создавать код на основе согласованных стандартов, как описано в данном курсе статей, а не для одного браузера. Сеть Web предназначена для всех, а не для элитной группы пользователей с современной конфигурацией. Так как рынок браузеров изменяется быстро, придется возвращаться к коду и продолжать его исправлять. Это неэффективно и неинтересно.
Если какое-то потрясающее свойство работает только в одном браузере, и вы действительно хотите использовать это, поместите этот код в свой собственный документ сценария и назовите, используя название браузера и версию. Это означает, что можно будет легко найти и удалить эту функцию, если этот браузер устареет.
Один из основных моментов, о котором надо помнить при обсуждении кода и
Короче, проверяйте, что все поступающие в систему данные являются хорошими и точно соответствуют тому, что требуется. Это особенно важно на сервере при записи параметров полученных из URL. В JavaScript очень важно проверять тип параметров, передаваемых функциям (используя оператор typeof ). Следующее будет ошибкой, если переменная members не будет массивом (например, для строки будет
function buildMemberList(members){
var all = members.length;
var ul = document.createElement('ul');
for(var i=0;i<all;i++){
var li = document.createElement('li');
li.appendChild(document.createTextNode(members[i].name));
ul.appendChild(li);
}
return ul;
}
Чтобы этот код работал правильно, необходимо проверять, что тип переменной members будет массивом:
function buildMemberList(members){
if(typeof members === 'object'
typeof members.slice === 'function'){
var all = members.length;
var ul = document.createElement('ul');
for(var i=0;i<all;i++){
var li = document.createElement('li');
li.appendChild(document.createTextNode(members[i].name));
ul.appendChild(li);
}
return ul;
}
}
Массивы являются коварными, так как говорят, что являются объектами. Чтобы убедиться, что это будет массив, проверьте один из
Другой очень небезопасной практикой является чтение информации из DOM и использование ее без сравнения. Например, однажды мне пришлось отлаживать некоторый код, который вызывал остановку функции JavaScript. Код, который вызывал это - по некоторым, не зависящим от меня причинам - считывал имя пользователя из innerHTML элемента страницы, и вызывал функцию с этими данными в качестве параметра. Так как имя пользователя может быть любым символом UTF-8, в том числе символами
То же самое применимо к формам, которые проверяются только на клиентской стороне. Я однажды подписался на недействительный адрес e-mail, перезаписав
Для доступа к DOM проверьте, что элемент, который вы хотите получить и изменить, в действительности доступен, и является тем, что вы ожидаете - иначе код может отказать или вызвать странные ошибки при отображении страницы.
Как можно видеть в некоторых из приведенных здесь примеров, создание большого объема кода HTML в JavaScript может быть достаточно сложным и ненадежным.
Особенно в Internet Explorer можно встретить всевозможные проблемы, изменяя документ, когда он еще загружается, и манипулируя контентом с помощью innerHTML.
С точки зрения сопровождения страницы также крайне плохой идеей будет создание большого объема разметки с помощью HTML, так как не каждый обслуживающий инженер будет иметь такой же уровень знаний как разработчик, и может потенциально действительно запутаться в коде.
Я обнаружил, что для создания приложения, которое существенно зависит от JavaScript, использование шаблона HTML и загрузка этого шаблона с помощью
В этом сценарии шаблон загружается, когда доступен правильный контейнер HTML, и после этого в setupPlayer() применяются обработчики событий.
var playercontainer = document.getElementById('easyyoutubeplayer');
if(playercontainer){
ajax('template.html');
};
function ajax(url){
var request;
try{
request = new XMLHttpRequest();
}catch(error){
try{
request = new ActiveXObject("Microsoft.XMLHTTP");
}catch(error){
return true;
}
}
request.open('get',url,true);
request.onreadystatechange = function(){
if(request.readyState == 4){
if(request.status){
if(request.status === 200 || request.status === 304){
if(url === 'template.html'){
setupPlayer(request.responseText);
}
}
}else{
alert('Error: Could not find template...');
}
}
};
request.setRequestHeader('If-Modified-Since','Wed, 05 Apr 2006 00:00:00 GMT');
request.send(null);
};
Таким образом, люди могут транслировать и изменять плеер любым образом, при этом код JavaScript изменять не требуется.
Вряд ли кто-то будет отрицать, что за последние несколько лет библиотеки и среды разработки JavaScript захватили рынок Web-разработки. И это совсем неплохо - если использовать их правильно. Все хорошие библиотеки JavaScript хотят одного и только одного: они хотят облегчить жизнь разработчика, решая проблемы несовместимости между различными браузерами и закрывая пробелы в поддержке браузеров. Библиотеки JavaScript предоставляют предсказуемую, функционирующую основу для построения.
Изучение JavaScript надо начинать сначала без библиотек, чтобы лучше понимать, что в действительности происходит, но после перехода к разработке Web-сайтов необходимо использовать библиотеку JS. Тем самым можно будет уменьшить количество решаемых проблем, и появляющиеся ошибки будут, по крайней мере, ошибками, которые можно воспроизвести - а не случайными проблемами браузера.
Я предпочитаю использовать библиотеку Yahoo
Хотя все библиотеки хорошо работают вместе, но использование нескольких библиотек в одном проекте не слишком хорошая идея. Это создает еще один дополнительный уровень сложности и обслуживания.
Последнее, что я хочу сказать, имеет отношение собственно не к JavaScript, а к тому, как это вписывается в остальную часть стратегии разработки. Так как любое изменение в JavaScript оказывает прямое влияние на производительность и функциональность Web-приложений, то весьма соблазнительно оптимизировать код насколько возможно, несмотря на последствия для обслуживания.
Существует множество приемов, которые можно применять к JavaScript, чтобы заставить его работать еще лучше. Большинство из них обладает тем недостатком, что делают код более сложным для понимания и обслуживания.
Чтобы писать безопасные, работающие сценарии JavaScript, необходимо прервать этот цикл и прекратить оптимизировать код для машин, а не для других разработчиков.
Более того - то, что очень часто встречается в других языках, но не так хорошо известно среди разработчиков JavaScript. Сценарий сборки может удалить пробелы, комментарии, заменить строки поиском в массиве (чтобы избежать создания в MSIE объекта строки для каждого отдельного экземпляра строки - даже в условиях), и сделать все остальные небольшие усовершенствования, необходимые для того, чтобы заставить код JavaScript летать в браузерах.
Если больше сконцентрироваться на создании начального кода, который легко понять и расширять другим разработчикам, можно создать прекрасный сценарий сборки. Если продолжать поспешно оптимизировать, мы никогда этого не добьемся. Создавайте не для себя или браузера - создавайте для следующего разработчика, который придет за вами.
Основная задача при использовании JavaScript состоит в том, чтобы избежать опасности легкого пути. JavaScript удивительно гибкий язык, и так как рабочая среда, в которой он выполняется, является крайне всепрощающей, легко написать небрежный код, который создает видимость выполненной работы. Тот же самый код будет создавать затем постоянные проблемы в течение нескольких месяцев.
Разработка JavaScript превратилась из области пограничного знания в абсолютную необходимость, если вы хотите получить работу в качестве разработчика Web.
Если вы начинаете именно сейчас, то вы счастливчик, так как многие другие уже сделали большинство ошибок, самостоятельно изучая язык
Крис Хайлман работает Web-разработчиком уже десять лет, с тех пор как бросил радио-журналистику. Он работает для Yahoo! в Великобритании в качестве инструктора и ведущего разработчика, и осуществляет надзор за качеством кода
Крис поддерживает блог на сайте Wait till I come (http://wait-till-i.com/) и доступен во многих социальных сетях под ником "codepo8".
Фото с разрешения: Bluesmoon (http://www.flickr.com/photos/bluesmoon/1545636474/)
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.