функции
Вкладка Согните страницу по вертикали,чтобы совместить два мозга и решить задачу. ^
Что дали вам функции? < г-
---------
\ Ы хороШ о, а ДВа ,ЩЧШе!
< г-
Установить мир во всем мире всегда сложно. Даже в JavaScript только самый систематизированный код даст вам спокойствие и уверенность. Комфортная жизнь дается нелегко, по крайней мере, в 1ауа8спр1.
у
ф о р м ы и ч^’ о Б е р к а д а н н ь х х
★
Пусть он все расскажет
Для получения информации от пользователей при помо щи иауаЗсг1р1 вам не потребуется быть джентльменом. Но вы должны быть аккуратны. Люди часто делают ошибки, а это озна чает, что данные, полученные при помощи веб-форм, далеко не всегда корректны. Проверяя вводимые данные при помощи JavaScript, вы увеличиваете надежность веб-приложений и снимаете дополнительную нагрузку с серверов. Полоса пропускания нам пригодится для восхити тельных видеороликов и чудесных фотографий.
ПОЛЯ данны х для баннера
Фирма ВаппегосКу Высококлассный летчик Говард решил превратить свою любовь к полетам в бизнес по развешиванию баннеров и основать фирму Ваппегос11у. Говард хочет придать новый вид понятию «баннерная реклама», принимая через Интернет заказы на воздушные баннеры. О н надеется, что новая система приема заказов освободит ему время для столь любимых полетов. Г овард р е ш и л извлечь х о р о ш у ю выгоду из эт о го аэр о п л а н а в р е м е н В т о р о й м и р о в о й войны.
Пр и номош,и веб-формы крайне важно собрать всю нужную для заказа баннеров информацию. Говард решил, что на странице кроме стандартных пунктов заказа должно быть еще и поле для ввода адреса электронной почты.
Текст Собственно текст объ явления.
Указывает, в каком именно регионе должно быть показа но объявление.
Даша полета О пределяет, когда бу дет вывеш ен баннер.
Email Телефон
(1мя И м я заказчика.
312
глава 7
К онтактная инф орм а ция заказчика.
Адрес электронной почты для связи с за казчиком.
формы и проверка данны х
HTML-форма П р и помощи Н Т М Ь первая форма Говарда приоб рела вот такой вид: Sannerodty - P « r s o « a t i z e d ^ i « J k y B a n n m
©00
CD
B A N N E R O C I T Y
Enter ms banner m essage: |
_______
Enter ZIP « Jd e of the tocation: | Enter the d ate for th e m essage to be s h o i^ : Enter your nam e; j
___________
Enter your phone number;
_
Enter your email address; | Order Banner
Эта форма для сбора заказов имеет все необхо димые поля и, кажется, готова"к работе даже без JavaScript. Так ли это? V
Форма заказов вы глядит здорово!
Говард с т о л ь ко л е т от работ ал л е т чи к о м . ч т о до сих п о р не м о ж е т ю а сст ат ься с кр а си б ой ф о р м о й .
^ * ^ ч а т ь ко д ф о р м ы м о ж н о п о адреса
5озьми в руку карандаш
^^ttpУ/www.headfirstlabs.com/booй/hfjs/
Давайте попробуем заполнить форму от руки. Не волнуйтесь, денег за рекламу нам платить не придется.
Enter the banner message; Enter ZIP code of the location: Enter the date for the message to be shown: Enter v^ur name: Enter your phone number; Enter your email address;
далее >
313
реш ение упражнения
Возьми в руку карандаш Решение М ы не знали,, ч т о д л и на баннера не м о ж е т п р е в ы ш а т ь 32- зн а ко в, и ввели с л и ш к о м д л и н ный т е к с т .
Вот каким образом мы заполнили предоставленную Говардом форму.
А м е р и к а н с к и е индексы с о с т о я т всего из п я т и циф р, в т о врем я ка к т у т у к а за н о ш ест ь.
■
Enter the banner message:
Mandango... выбор мест в кино для настоящих
Enter ZIP code of the (ocatton: 100012 ^ Enter the date for the message to be shown: Enter your name:
1 1 ,2009
Seth Tinselman
/ Ш е г i^ur phone number: |(212) Enter your email address: И м я за ка зч и ка о порядке.
March
555-5339
setht@mandango
В адресе э л е кт р о н н о й ^ п о ч т ы долж ен бы т ь у к а за н до м е н , н а п р и м е р .biz.
Номер т еле ф она следовало ввест и 6 виде
7 А б о т дат у т ребова лось у к а з а т ь в ф о р м а т е М М /Д Д /Г Г Г Г .
без всяки х скобок.
Когда языка НТМ1 недостаточно Говард убедился, что без помощи JavaScript, который будет про верять корректность вводимой информации, ему не обойтись. Кроме того, ему нужно донести до пользователей, какие именно данные считаются «корректными». Ведь без подсказки невозмож но догадаться о 32-символьном ограничении на текст баннера или о том, что дату следует вводить в форме ММ/ДД/ГГГГ.
Enter the banner
глава 7
О
message: | Mandango... выбор мест в кино для настоящих
J a v a S c rip t п о м о ж е т и зб е ж а т ь ввода не к о р р е к т н ы х данных.
314
Прошу прощения, но длина текста ограничена 32 символами.
В о т т о л ь ко ф о р м ы ) H T M L не у м е ю т р а зг о в а р и в а т ь !
О сновная проблем а состоит в том, что все умение JavaScript управляться с данны ми не помож ет Говарду, пока он не поймет, каким образом предоставить5ауа8сг1р1 доступ к вводимой в форму инф орм ации...
ф ормы и проверка данны х
Д оступ к данным формы Получение доступа к введенным в форму данным нужно начать с идентификации каждого из нолей. Такая задача решается средствами H T M L при помощи одного или двух атрибутов. кш ьны Т об р^оТ за ^
I
Э д е т поле ф о р м ы .
А т р и б у т id уникальным оа~
id = "zip co d e " name="zipcode"
<input
type="text"
size="5"
/>
р азо/л зад йе т лю бой э л е м е н т ст р а н и ц ы .
Enter ZIP code of the location: Iw o iT
I
------------
О эт их ат рибут а служ ат О ба ба эн идент ввода.
Наличие двух идентификаторов объясняется существованием нескольких способов получения доступа к полю. Во-первых, с помощью функции g e tE le m e n tB y ld ( ) .Этот способ прекрас но работает, но есть и более простая альтернатива. Каждому полю фо рмы соответствует объект form , который можно передать функции, проверяющей корректность введен ных данных. <input
id="zipcode"
name="zipcode"
type="text"
size="5"
o n c l i c k = " s h o w I t ( t h i s .f o r m ) " />
Объект fo rm представляет собой массив, содержащий все поля формы. Пр и этом индексы массива не являются числами; их роль играют уникальные значения атрибутов name! Поэтому при передаче функции объекта fo rm в виде аргумента с именем t h e Form доступ к полю ZIP code осуществляется следующим образом: П оказано значение по л я Z IP code. И м я аргум ент а.
У
function
showit(theForm)
{
100012
a l e r t (theS’o rm ["zip co d e "] .v a lu e ) ; };
И м я поля ф о р м ы , з а данное 8 а т р и б у т е п а т е т ега < in p u t> .
J
Н а м т р е б у е т с я не с а м о п о л е , а хра нящ е е ся в нем значение.
Данный способ доступа к данным ф о рмы не лучше и не хуже, чем доступ с помощью функции g e tE le m e n tB y ld (), но он проще для восприятия и требует меньшего количества кода.
далее >
315
когда нужна проверка Ч асто ^аД аБ аеМ ы е Б о І їр о С ь і'
Почему даже отдельное поле формы имеет доступ к объекту form? кобт
0:
I Иногда это не так, но следует помнить, что поля формы могут вызывать функцию проверки, которой требуется доступ к данным. В этом случае удобный доступ к остальным полям формы обеспечивает именно объект
form.
Этот объект
обычно передается функции проверки, поэтому она может быстро получить данные из любого нужного ей поля. Вы в этом еще убедитесь на примере с формой Bannerocity.
То( ) есть значение является свойством ПОЛЯ формы? То есть все ПОЛЯ формы являются объектами?
0 :,I Да. Каждое поле формы в коде JavaScript представлено объектом form, который предоставляет быстрый и легкий способ доступа к введенной в поля информации. Запись вида
f о rm [" оЬ j е с tn a m e " ] дает доступ к значению при по мощи свойства v a l u e . Но об этом мы поговорим в главах 9 и 10.
Я только что узнала, насколько важен до ступ к данным в JavaScгipt. Ведь именно он позволяет проверить их корректность. Но как понять, когда требуется проверка?
Проверку данных следует производить сразу после их ввода. Это означает, что ответ на вопрос «Когда произво дить проверку?» связан с событиями. Нужно знать, какое именно событие позволяет обнаружить ввод данных в поле. Именно с ним м ы познакомимся в сле дующем разделе.
316
глава 7
ф ормы и проверка данны х
Цепочка событий Ввод данных в форму сопровождается целым рядом событий. Эти события можно использовать как точку входа для операции проверки данных. Рассмотрим типичную последовательность действий при вводе информации, чтобы понять, какие именно события при этом возникают и в какой именно момент.
О
Выделите поле (опГосиз).
©
Введите данные.
е
о о
Ввод данных в поля формы сопровождается целой цепочкой событий Дауа8спр1.
Перейдите к следующему полю (опЫиг/опсЬапде). Выделите его (onf ocus). Введите в поле данные... 0
onfocus!
------
Enter the banner message: |м ^ а п д о ... Enter Zip code of the location:
100012
выбор мест в кино для настоящих мужчинГ onblur! . 0 onfocus!
0
OonchangeT
Enter the date for the message to be shown; Enter your name; Enter your phone number: Enter your email address:
При выделении поля появляется событие оп£осиз, в то время как снятие выделения сопровождается событием опЫиг. Событие опсЬапде в отличие от события о п Ы и г появля ется в случае, когда с поля снимается выделение, но его содержимое уже было изменено.
Ш ТУРМ Какие из вышеупомянутых событий нам потребуются для проверки данных?
далее ►
317
виж у л и я что-нибудь?
Событие onblur Было бы логично начинать проверку данных после события o n c h a n g e , но непонятно, как при этом поступать с пустыми полями. Ведь для них ничего не изменилось, даже если поль зователь и выделял такое поле в процессе заполнения формы. Проблема решается при помош;и события o n b l u r , возникаю щего при потере объектом фокуса.
onfocus!
Фокус на поле означает го товность к вводу данных.
Событие onblur является замечательным сигналом к началу проверки данных. Поле осталось пуст ы м , как заказчик не указал своего имени.
Enter your name: ][ ^оле теряет фокус.
Текстовое поле оказывается в фокцсе его и «ользобйтель выделил его щелчком или нажат ием клавиши
В отличие от события o n c h a n g e , событие o n b l u r возникает вне зависимости от того, были ли введены в поле данные. Таким образом, событие o n b l u r , конечно, является полезным инструментом, но нужно внимательно отслеживать, когда и как вы применяете его для уведомления пользователей о ре зультатах проверки данных. чаап° ^адаБ аеМ ы е
БоЦроСЬ! я правильно понимаю, что ряд событий возникает по сле ввода данных пользователем?
• Что означает это странное название o n b lu r ? I Событие o n b l u r является противоположным по смыслу
Q ; Да. в ответ на нажатие клавиш появляются события
onkeypress, onkeyup, onkeydown и т. п. Иногда имеет смысл написать реагирующий на них код, но для проверки инфор мации они не подходят, так как окно с предупреждением будет появляться еще до завершения ввода. Фактически это приведет к появлению уведомлений о каадой опечатке и каждом незавершен ном фрагменте информации. Поэтому лучше дождаться момента, когда пользователь покинет поле. Именно в этот момент появляется событие onblur.
318
глава 7
событию
o n f оси S. То есть если событие o n f o c u s
возника
ет в момент фокусировки на поле, то время события o n b l u r наступает после потери полем фокуса. Даже слово «фокус» в данном контексте неточно отражает смысл происходящего, но именно от него пошло слово «Ыиг» (размывание), указывающее на отсутствие фокуса.
ф ормы и проверка данны х
Сообщение проверки Самым простым способом быстро донести до пользователя нужную информацию является использование всплывающего окна. Именно таким способом пользователей уведомляют о некорректном вводе данных. Для этого нужно вызвать функцию alert {) при обработке события onblur.
Проверим, введены ли данные в поле формы.
function validateNonEmpty(inputField)
{
// Проверка на наличие текста
Ф у н к ц и я п р о в е р ки вы зы вает ся для по л я п а т е .
if (inputField. value.length == 0) { // Сообщаем пользователю, что данные не введены a l e r t ( " P l e a s e e n t e r а v alue.");
И нф ормация о т о м , к а к уст р а н и т ь проблему. Пользователя просят ввест и данные.
return false;
return true;
Please enter а value. Т а к к а к поле n a m e являет ся п у с т ы м , вы зы ваем окн о с с о общ ением .
Возьми в руку карандаш С кол ько собы тий
%
onblur
появляется при такой последовательности
ввода данных? А с ко л ь ко собы тий
Enter your name:
onchange?
e in w ^ Seth Tinselman
Enter your phone num Enter your email address:
setht@mandango
Событий onblur: Событий onchange:
далее >
319
собы т ия onblur и onchange лицом к лицу
Возьми в руку карандаш_ _ _ \
Рош оиыр
Enter your name:
Вот сколько событий onblur и onchange появляется при таком способе ввода данных.
Seth Tinselman iseiman у
onbhtf!qj onchange!
Enter your phone numb Enter your email address: —
setht@mandango
onchange!
—
Событий onblur: ..^ Событий onchange:
Беседа у камина Собы тия onblur и onchange решают, когда следует реагировать на некорректные данные.
onblur:
onchange:
Кажется, в наши дни сценарии только и за ботятся об отслеживании действий пользо вателей. Вот тут-то я и пригождаюсь.
Именно об этом я и хотел с тобой погово рить. Ходят слухи о каких-то пустых полях. И все показывают пальцем на тебя.
Это да. М ы всегда даем знать, если элемент форм ы вдруг оказался измененным или по терял фокус... или все сразу!
Честно говоря, твой намек меня шокирует. Т ы же знаешь, что я всегда оповещаю о лю бых внесенных в форму изменениях. Так никто и не сомневался в твоей способ ности реагировать на изменения. Н о вот как ты поступаешь в случае, когда в поле так ничего и не ввели?
320
глава 7
ф ормы и проверка данны х
onblur:
Вот именно. Это не имеет смысла. Точно так же, как здравый смысл отсутствует у многих пользователей, но при этом они заполняют формы.
onchange; Т ы утверждаешь, что пользователь может попытаться отправить форму с незаполнен ными полями? Н о это же не имеет никакого смысла.
Хорошо. Рассмотрим форму, в которой пользователь не заполнил некоторые поля, но тем не менее решил ее отправить... черт., мне страшно!
Не волнуйся, ты тут ни при чем. В конце концов, данные, оставшиеся без изменений, не твоя забота. Тебя зовут onchange. Н о как же быть с предложенным тобой сце нарием, при котором отправляется форма с незаполненными полями? Я уже сказал, что это не твоя забота. Просто, если для сценария важно, чтобы все поля были заполнены, ему не следует прибегать к твоим услугам.
Не стоит так нервно реагировать. Ты, ко нечно, не очень подходишь для запуска кода проверки, но это не означает, что сценарию не нужно узнавать об изменении данных. Ведь есть еще и формы, позволяющие редактировать хранящиеся в других местах данные. Т ы можешь запускать процедуру сохранения, только если изменения были действительно внесены.
Рад это услышать, даже если твое утвержде ние и означает, что со мной вообще не надо работать. О боже, мне опять плохо...
Да, действительно. Получается, что от меня все-таки есть польза? Конечно! Так что не переживай. Спасибо. Т ы меня обнадежил. Пожалуйста. Рад был с тобой поболтать, но мне нужно проверить достоверность вон тех данных.
далее ►
321
есть ли тут что-нибудь?
ищем... что-нибудь Вернемся к странице Bannerocity. Говард понимает, что ему для начала следует проверить, были ли введены данные в поля его формы. С точки зрения JavaScript эта задача выглядит немного по-другому. Лучше проверять не отсутствие данных в поле, а их наличие. Другими словами, «что-то» — это «не ничего».
Что-то
Не ничего
Причиной такого парадоксального на первый взгляд подхода является тот факт, что намного проще проверить отсутствие данных. Не п у с м о .
Enter your name:
Seth Tinselman
Enter youf phone number: П уст о .
Функция проверки должна реагировать на событие onblur для каждого из полей, проверяя, не осталось ли поле пустым. Например: Поле ф о р м ы и м & с т у н и ка л ьн ы е и ден т и ф икат о ры , эт о пр е д о с т а в л я е т к н е м у д о с т у п из д р у г и х ч а ст е й сценария. <input
id="phone"
name="phone"
type="text"
size="12"
onblur="validateNonEmpty(this);"/> /К Ф у н к ц и я v a iid a te N o n E m p tu O вы зы вает ся в о т в е т на с о aw m ue o n b lu r и п р о в е р я е т , введены ли в поле данные
Ключевое слово this является ссылкой на поле формы. Передавая поле в виде объекта функции проверки, оно предоставляет доступ к введенному в это поле значению. Ведь все поля формы содержат именно объект form.
322
глава 7
Поле ф о р м ы п е р е д а е т _ся ф у н к ц и и п р и п о м о щ и клю чевого слова
ф ормы и проверка данны х
проверка полей на наличие данных Для каждого из полей формы существует код, связывающий событие о п Ы и г с функцией validateNonEmpty (). Это обеспечивает проверку всех полей.
< in p u t id = "n a m e " nam e="nam e" t y p e = " t e x t "
s iz e = " 3 2 "
o n b lu r = " v a lid a t e N o n E m p ty (t h i s ) ; " / > Поле п а т е ф у н кц и я п р о в е р я е т на н а л и чие им е н и .
ф ц н т и я п р о в е р я е т поле pho n e n u m b e r на наличие те л е сЬ о н н о го м Ш £ а . --function validateNonEmpty (inputField) // Проверка на наличие
{
С войст во le n g th за д а е т ко ли че ст во с и м во л о в в ст р о ке .
--
if (inputField.value.length == 0) ( // Сообщаем пользователю, что данные не введены al e r t
("Please enter а value.");
Телефонный номер не введен, п о э т о м у
ф ункция возвращ а е т значение false и от кры вает окно с предупреждением-
return false;
И м я в поле о б н а р у ж е но, п о э т а м и ф у н кц и я возёраицает значение tru e .
return true;
1
Please enter а value.
В данном примере пока никак не задействованы значения, воз вращаемые функцией validateNonEmpty (). О н и сообщают вызвавшему функцию коду о результатах проверки: true, если данные обнаружены, и false в противном случае. Немного позже вы увидите, каким образом эти значения используются для обеспечения корректности данных перед отправкой их на сервер для дальнейшей обработки.
Функция проверки гарантирует заполнение всех нолей формы.
Ш ТУРМ Какие недостатки имеет всплывающее окно с оповещением о вводе некорректных данных?
далее у
323
не будем раздражат ь пользователей
Проверка без предупре)кдаюцих всплывающих окон Говард быстро сообразил, что всплывающие окна не самый лучший способ информирования о вводе некорректных данных. Слишком много жалоб поступало от потенциальных заказчиков. Ведь рано или поздно любого начинает раздражать, когда ввод данных прерывается появлением окна. Пусть даже в этом окне и содержится нужная пользователю информация. у,
„
Н овы й H T M L -э л е м е н т п р е д о с т а в и л м е с т о для ‘и н ф о р м а ц и о н н о го с о -
1овард решил переити к «пассивным подсказкам», которые не пре- общения рывают процесс ввода. О н предпочел добавить к форме несколько элементов НТМЬ.
Enter your phone number:
P fe a s e e n t e r a v a lu e .
Новые H T M L -элементы позволяют донести до пользователя полезную информацию без участия всплывающих окон. Достаточно добавить тег <span> ,задающий контейнер для внутреннего текста. г / г_ Этот тег появляется в коде веб-страницы сразу под полем input.
В т о р о й а р гу м е н т ф у н кц и и
va lia a teN o n tm p у и т е м р ь передает ся ^ вспом огат ельны м т екст ом .
< in p u t id="phone" name="phone" ty p e = " te x t" size= "1 2 " o n b lu r= " v a lid a te N o n E m p ty (th is, docum ent. g e tE le m e n tB y ld ( 'p h o n e _ h e lp ') ) " /> <span id= "phone_help" c l a s s = " h e lp " x /s p a n >
Тег <span> изначально являет ся п у с т ы м , но он и м е е т IP , связанное с полем ф орм ы phone n u m b e r.
Д л я ф о р м а т и р о в а н и я вспо м о г а т е л ьн о го т е к с т а и с п о л ь зу е т с я с т и л ь class В р е з у л ь т а т е он п и ш е т с я наклонны м ш р и ф т о м к р а с ного ц в е т а , х о т я в книге эт о го и не видно! С овпадение э т и х двух и д е н т и ф и к а т о р о в о бе с п е ч и ва е т появление в с п о м о га т е л ьн о го т е к с т а в поле ввода.
Итак, м ы вставили элемент span, содержащий вспомо гательный текст, и теперь нам требуется код, который будет его отображать. Сделаем ответственной за эту операцию функцию validateNonEmpty ().
324
глава 7
ф ормы и проверка данны х
УсАО}княем наш Валидатор Новый подход к вспомогательным сообщениям заставляет нас от редактировать функцию v a lid a te N o n E m p ty (). Теперь она должна еще и отображать и убирать текст из полей формы.
fu n c tio n v a lid a te N o n E m p ty (in p u tF ie ld , //
h e lp T e x t)
О б ъ е к т h e lp te x t п е р е да е т ся ф у н кц и и в ка че ст ве вт орого аргум ент а.
{
П роверка на н али чи е т е к с т а
if (InputField.value.length == 0) ( //
Сообщаем п о л ь з о в а т е л ю , ч т о данн ы е н е в в е д е н ы
if (helpText != null)
-----
helpText.innerHTML = "Please enter a value."; re tu rn
e ls e
fa ls e ;
(
/ / Данные о бн ар у ж ен ы , у б и р а е м в с п о м о г а т е л ь н ы й текст if
(h e lp T e x t
!= n u l l )
Убеж даем ся, чт о э л е м е н т h e lp te x t сущ ест вует (h e lp T e x t != n u ll), ■и присваиваем свой с т в у in n e rH T M L в с п о м о га т е л ьн ы й т екст .
Н у ж н о сде л а т ь т а к , чт обы после ввода данны х ■ всп о м о г а т е л ь н ы й т е к с т исчезал из поля.
-^ Г "
helpText.innerHTML = return true;
тш
Проверка данных на странице Bannerocity стала заметно лучше благодаря новому подходу. М ы все еще используем для этой цели JavaScript, но уже более деликатным способом.
Enter ZIP code of m e loMtior,: [ Enter the d ate for the m essag e to b e shown:
Теперь вам не будут надоедать всплывающие окна. ■V
m m r a Ш иб. m a s e enter a value.
Enter your nam e: | S e th T in selm an Enter your phone nymber: |
' Please enter a value. ' m e s s enter а value.
Enter your email address: f
Если данные о т с у т с т в у ю т , в поле о т о б р а ж а е т с я просьба и х ввест и.
Т а к к а к все введено, в с п о м о га т е л ьн ы й т е к с т не появляет ся.
далее ►
325
оно помест илось?
Хорошенького понемно>кку Наша проверка на наличие данных работает отменно, но за думывались ли вы о том, что избыток может быть так же вреден, как и недостаток? Чтобы понять суть проблемы, достаточно посмотреть на последний заказанный Говарду баннер. На баннер п о м е с т и л а с ь т о л ь ко ч а с т ь т е кст а ... С ет с Д ж е й с о н о м р в у т .
ы м еч у т?
^
ШТУРМ Что же случилось с баннером и каким об разом можно решить данную проблему?
326
глава 7
формы и проверка данны х
Размер имеет значение... Проблема в том, что на воздушном баннере помещается всего 32 символа, в то время как в соответствующее поле можно вво дить фразы произвольной длины. Пока что появляется только вспомогательное сообщение о необходимости ввода данных, но нигде не написано об ограничениях на ввод. Вот и причина проблем Говарда!
Enter the banner message:
5 ы л введен с л и ш к о м длинны й т е к с т , но п о льзо ва т е ля не проинф ормировали 00 э т о м .
Mandango... выбор мест в кино для настоящих мужчин'
Т а к к а к весь т е к с т не с м о г п о м е с т и т ь ся нд баннере, он был обрезан...
Невозможно поместить неограниченное количество символов на ограниченное место, а в результате м ы имеем недовольных клиентов. Значит, требуется проверять еще и длину вводимых фраз. Разумеется, снабдив форму еще одним вспомогательным сообщением для пользователей.
Новы й т е к с т ограничен ЗЯ сим волам и.
Enter the banner message: Mandangc-.. места для w А т е к с т , не п р е в ы ш а ю щ и й заданного л и м и т а , п р е к р а с н о п о м е с т и л с я на баннере.
Возьми в руку карандаш Напишите псевдокод, демонстрирующий работу функции, которая проверяет длину сообщений. Не забудьте проверить не только максимальную, но и минимальную длину.
далее >
327
проверка длины
Возьми в руку карандаш Решение А р гу м е н т а м ф унк~ ции m in L e n g tk и m a x L e n g th следует п р и с в о и т ь значения i м Ъ7- с о о т в е т ст венно.
Вот принцип работы функции, проверяющей длину вводимых в поле сообщений.
длиннее, чем m axLenyth) „ „ Показашь оспомогательныи текст
Else Убрать вспомогательный текст
Проверка длины Новая функция v a l i d a t e L e n g t h () должна проверять, не вы ходит ли длина сообщения за отведенные границы. В случае с Bannerocity она должна проводить ограничения сверху, хотя проверка на минимальное количество символов в нее тоже встроена. На всякий случай. Причина в том, что Говард сомне вается в существовании клиентов, которые захотят написать на баннере всего одну букву.
h e lp T e x t) ;
Новой функции потребуется таюке аргумент для поля ввода и вспомогательный текст, призванный помочь пользователю правильно составить фразу. То есть всего у функции будет четы ре аргумента.
m in U n g th
— ^
maxLength Максимальная длина вводимо го в поле текста.
............^ i n p u f F i e l d ..........
М инимальная длина вводимого в поле текста.
П оле, количество символов в котором проверяется.
Элемент, отображ аю щ ий вспомогательны й текст.
< in p u t id="m essage" name="message" ty p e = " te x t" size= "3 2 " onblur="validateLength(l, 32, this, document.getElementByld('message_help'))" /> <span id = "m essage_help" c la ss= " h e lp " > < /sp a n >
~—
Функция v a l i d a t e L e n g t h {) берет значение аргумента i n p u t F i e l d и проверяет, что это значение имеет (как минимум) длину, заданную параметром m in L e n g th , но не превышает па раметра m ax L en g th . В случае слишком короткого или слишком длинного значения в элементе h e l p T e x t появится подсказка.
328
глава 7
^ ? o fo T T o л T в fo д 7 fл 7 Z 7 к c ^ ^ a баннера.
формы и проверка данны х
> КЛЮ ЧЕВЫЕ МОМЕНТЫ
л
Все поля формы являются объектами JavaScript. Каждое поле формы имеет свойство fo rm , пред ставляющее всю форму в виде массива полей. Событие o n b lu r возникает при потере объектом фокуса, и именно оно запускает функцию проверки
Всплывающие окна — не самый лучший способ ин формирования пользователей о проблемах с вводом данных. Пассивный подход к проверке данных меньше раз дражает пользователей. Свойство l e n g t h указывает на количество симво
данных.
лов в строке.
Возьми в руку карандаш Напишите код функции v a l i d a t e L e n g t h ( ) , уделяя особое внимание передаваемым ей аргументам.
function
/ /
validateLength(minLength,
maxLength,
inputField,
helpText)
{
Смот рим, содержит ли т екст как м и ни м ум m inLength, но не 5ольиле m axLength символов.
/ / С ообщ аем п о л ь з о в а т е л ю о б^оде н & к о р р е к т н ш
.................................
/ / С д а н н ы м и все в п о р я д ке , у б и р а е м п о д с ка зку .
}
далее ►
329
реш ение упражнения
Возьми в руку карандаш 'ешение function
Вот как выглядит код функции v a l i d a t e L e n g t h ().
validateLength(minLength,
maxLength,
inputField,
helpText)
{
«« больше m axLength символов
П роверяе м к а к
i f (in p u tF ie ld .v a iu e .le n g th < m in L e n g th in p u tF ie ld .v a lu e .le n q th > m a x L e n a th ) ( ..............' 3 ? ^'....................... ..................................................... .......................... v .... л .
т ак и м ини/ / С ообщ аем п о л ь з о в а т е л ю о вводе н е к о р р е к т н ы х данны х м а л ь н у ю д л и н у ........................................................................................... ............................................................................ вводим ого ,jf,( h e lp T e x t != n u ll) в поле т е к с т а .' +■ " i o " + t ^ a x L e n g t h +
c h a ra c te rs in le n g th ."; r e t u r n false; У ведом ление 0 т о м , чт о вводим ы й т екст огр а ничей сверху
г ............................................................................................................ г ................................................................................................
к о л и ч е ст в у
9.
сим волов. Г
.
б п о р яд ке , у б и р а е м п о д с к а зк у
-п ,, , , ,,, (Г (h e lp T e x t != n u ll) ■
П ри вводе коррект но го т е к с т а убираем по д ска зку.
he Ip T e xt. іп п е г Н Т М L = r e t u r n tr u e ; I
Проблема с те к сто м решена Говард может вздохнуть с облегчением. Ведь у него пока нет денег на покупку большего баннера, поэтому он может решить проблему только на уровне JavaScript. П о крайней мере теперь пользователи будут узнавать об ограничении на длину текста до того, как сделали заказ.
В спом огат ельны й т е к с т появляет ся ілри вводе с л и ш к о м больш ого ко л и ч е ст ва сим волов.
Enter the banner message: jcet your adventure on with Stick Figure Adventure! Pioase entof a value 1 to 32 characters in length. |
330
глава 7
ф ормы и проверка данны х Часзцо З адаваем ы е В опросы
Чем так плохи всплывающие окна? Разве большинство пользователей не понимает, что это не реклама?
Какую роль играют атрибуты n a m e и i d при связывании вспомогательного текста с полем ввода?
! К сожалению, раздражающими являются любые действия, которые
основан на атрибутах i d / n a m e связанного с ним поля ввода, но это
заставляют человека прервать свое занятие, чтобы закрыть появившееся окно. Именно поэтому мы крайне не рекомендуем использовать всплывающие окна при проверке данных.
вовсе не одно и то же. Идентификатор вспомогательного текста получается из
; Атрибут i d элемента h e l p t e x t
слова t h i s в коде для события o n b l u r . Объектом является поле или сама форма?
ID поля ввода добавлением _ h e l p . Подобная система именования позволяет создать прозрачную связь между полем и элементом, отображающим в этом поле текст подсказки. Хотя выбирать имя для идентификатора элемента h e l p t e x t можно и самостоятельно, главное, чтобы оно было уникальным и корректно передавалось в функцию проверки.
Q ; Оба ответа верны. В HTML ключевое слово t h i s ссылается на элемент как на объект. То есть в случае поля t h i s это ссылка на объект «поле». Этот объект обладает свойством f o r m , дающим доступ к форме. То есть запись t h i s . f o r m в коде, связанном с событием o n b l u r , означает ссылку на форму, как на объект. Написав t h i s . f o r m в коде Bannerocity мы получим доступ к элементу «вспомогательный текст», связанному с определенным полем ввода. Запомните, что t h i s . f o r m — это ссылка на объект f o r m , который представляет собой массив со всеми полями формы. Поэтому для быстрого доступа к полю с именем
ту_
f i e l d достаточно написать t h i s . f o r m [ " m y _ f i e l d " ] . Аналогичный результат можно получить и с помощью функции g e t E l e m e n t B y l d ( ) , но продемонстрированный выше подход является более лаконичным.
Зачем удалять вспомогательный текст, если проверка показала корректность введенных данных? ; Назначением вспомогательного текста является помощь пользователю при возникновении проблем. Если же данные введены корректно, проблемы нет и нет причины для отображения подсказки. А так как подсказка может оказаться видимой из-за более ранних проверок данного поля, в случае когда пользователь все ввел правильно, имеет
Q * Сценарий будет снова и снова искать отсутствующий элемент, раскалит страницу до красна и оставит от браузера обуглившиеся остатки. Шучу, на самом деле просто исчезнет система пассивной помощи пользователям на странице Bannerocity И вспомогательный текст перестанет появляться. Это говорит о необязательности данной функции. То есть вы можете по желанию убрать подсказки или вывести их только для отдельных полей формы. Если код проверки увидит, что аргумент
helpText имеет значение, отличное от null, значит, нужный нам элемент существует и может быть отображен.
Ограничивает ли атрибут size поля формы длину вводимого сообщения? ! Нет, HTML-атрибут size ограничивает только физический размер поля формы на странице — на количество вводимых символов он никак не влияет. К примеру, для поля ZIP code на странице Bannerocity атрибут size имеет значение 5, что означает возможность показа только пяти символов. Но, чтобы ограничить длину вводимого текста, потребуется уже атрибут maxlength. Функция проверки позволяет достаточно гибко управлять количеством вводимых символов. Так, в случае с индексами имеет смысл не только офаничить максимальное количество пятью, но и проверять, являются ли вводимые символы цифрами. Подозреваю, что Говард в один прекрасный момент захочет это реализовать.
смысл ее удалить.
Что произойдет, если элемента h e lp t e x t не окажется в числе аргументов функции проверки?
Б
далее >
331
где т ы ?
Некорректное местополо)кение Несмотря на все усилия Говарда по проверке вводимых в форму данных, он снова и снова сталкивается с проблемами при приеме заказов. На этот раз пользователь ввел неправильный индекс, и Говард несколько часов летал над совсем другой местностью. Больше всех от этой ошибки постра дал Дункан, так надеявшийся на новых потенциальных любителей своих пончиков. Еп1ег 2!Р сос1во1т е 1о<я1Ьп;
Введенная заглавная I ол4есто ц и ф р ы я была в о с п р и н я т а к а к циф ра 1 .
О сш сап’з В о п ^ 'З
Я и не мог надеяться на такую удачу. Баннер Дун кана показали над другим штатом! Вот так обычная опечатка стала причиной ошибки ввода данных и привела к полной путанице. Клиент нечаянно нажал I вме сто 9, ведь эти клавиши расположены рядом. Говард же решил, что I — это 1, и вывесил баннер совсем в другом месте.
П ом нит е Ф ренки, к о н к у р е н т а Д ункана.
ГШ ТУРМ Как проверить правильность ввода индекса?
332
глава 7
ф ормы и проверка данны х
Н и к а к и х букв.
Проверка индексов Итак, очередная проблема Говарда связана с неверно вве денным индексом. В С Ш А индексы состоят из пяти цифр. Поэтому для начала следует проверить, чтобы клиент ввел именно пять цифр — ни больше, ни меньше. 37205
С л и ш ко м длинный.
робно Пйть
# # # # #
цифр-
о кг С лиш ком ^ ко ро тки м -
Возьми в руку карандаш Закончите код функции v a lid a t e Z I P C o d e ( ) , проверяющей правильность ввода индексов.
function // if
validateZIPCode(inputField,
Проверяем
количество
вводимых
)
( // if
Если
их
количество
(helpText
не
helpText)
символов.
{
Их
должно
быть
ровно
5
{
совпадает,
показываем
подсказку
!= n u l l )
helpText.innerHTML
=
"Введите
ровно
пять
цифр.";
} //
Проверяем,
else // if
if
что
все
символы
(
Если
являются )
данные
(helpText
введены
числами
{
некорректно,
показываем
"Пожалуйста,
введите
подсказку
!= n u l l )
helpText.innerHTML
=
число";
} else // if
{ Данные
введены
(helpText
корректно,
убираем
подсказку
!= n u l l )
helpText.innerHTML
=
"";
далее ►
333
реш ение упражнения
Возьми Вруку карандаш Р рш рц ы р
как выглядит функция v a l i d a t e Z I P C o d e ( ) , проверяющая корректность ввода индексов.
Д л и н а введенной с т р о ки д о л ж н а с о с т а в л я т ь ^ 5 сим волов. function
■'N.
validateZIPCode(InpLtField,
//
Проверяем
if
{
helpText)
вводимых
символов. Их
in p u tF ie ld .v a lu e .le n g th
!=
{
Если их количество ( h e l p T e x t != n u l l )
не
// if
количество
h e l p T e x t .i n n e r H T M L
,
=
S
)
совпадает,
"Введите
{ должно
показываем
ровно
пять
быть
5.
подсказку
цифр.";
______ ипАичест во введенных
р ,
}
в о звр а щ а е т ся значение w ise.
//
Проверяем,
else // if
if
что
все
символы
Если
данные
(helpText
введены
r e t u r n fa k e ........................ ........
=
~~
} // if
числами
■
ф у н кц и я isN aN Q п р о в е р я е т , р а вен ли а р г у м е н т зн а ч е н и ю N a N (н е -ч и с л о ).
некорректно,
показываем
"Пожалуйста,
введите
подсказку
!= n u l l )
h e l p T e x t .i n n e r H T M L
else
являются
^ ------------( is N a N (in p u tF ie ld .v a lu e ) ) { .........................................................
число";
^ введены с и м в о л ы , о т л и ч н ы е о т чисел, во звр а щ а е т ся значение false.
{ Данные
введены
(helpText
корректно,
убираем
подсказку,
!= n u l l )
helpText.innerHTML
=
Показанная выше функция не универсальна. Больш е I осш орож ны !
334
глава 7
Например, она не подходит для проверки индексов других стран. Существуют страны, в которых индексы составлены не толь ко из цифр, но и из букв. Более того, американские индексы в полной форме состоят из 9 цифр и имеют вид #####-####. На личие дефиса делает индекс нечисловым.
ф ормы и проверка данны х
А что произойдет, если клиент не будет обра щать внимания на вспом огательны е сообщения? Будет л и заполненная и м форма с данным и все равно отправ лена на сервер?
Некорректные данные отправляться не должны. В конце концов, зачем нужен код проверки, если пользователь все равно может отправить неверно введенные данные? На странице Bannerocity пока что отсутствует процедура проверки информации перед отправкой содержимого формы, а значит, не исключе на вероятность дальнейших ошибок. П р оверка к о р р е к т н о с т и не и м е е т с м ы с л а , если п о л ьзо ва т е л ь и м е е т в о з м о ж н о с т ь п р о и г н о р и р о в а т ь все п р е д у п р е ж д е н и я и все р а вн о о т п р а в и т оанные.
о gantieroclw -
b
a
n
n
e
r
o
c
i t
y
/ Pfease m tera value 1 to 32 chemoter$ in length. Enter the banner message: | ptease enter exsclly ffve dftte.
Enter ZIP code of the tocatton:
Enter the date (or the message to be shown:
" "
Enter your nanne; | Enter your phone number: j
Явз8в enter a value, nsase enter a vatas.
_ ' Please enter a value.
Please enter в value.
Enter your emaB address: | Order Banner
Самы е уст о й чи в ы е п р и л о ж е н и я на всякий сл уч а й п р о в е р я ю т д а н ные еще и на сервере.
Н у ж н о , чт обы щ е л ч к о м на к н о п ке O r d e r B anner от правит ь м о ж н о было т о л ь ко к о р р е к т н ы е данные.
У
Таким образом, странице Bannerocity требуется еще одна функция, которая будет проверять все поля фор м ы перед отправкой данных на обработку. Эту функцию placeOrder () м ы свяжем с кнопкой Order Banner, и имен но она будет осуществлять финальную проверку.
< in p u t t y p e = " b u t t o n " v a lu e = " O r d e r B a n n e r" o n c l i c k = " p l a c e O r d e r ( t h i s . f o r m ) ; "
/>
далее >
335
сделай заказ и удостоверься
|J o A j3 o g H o о « ф у н к ц и и
f la c e O r J e r ( )
8 ка че ст ве а р г у м е н т а ф у н к ц и и п е р е да е т ся о б ъ е к т fo r m , ч т о дает ей д о с т у п к полям ф о р м ы ,
^ элем ент ам n Z t Z o K о сущ е ст в л я е т ся ч е Т е Т ^ ^ ъ е к т fo r m п о и н й к с а м м а сси ва .
function placeOrder(form if
( v a l i d a t e L e n g t h (1,
32,
f o r m [" m e s s a g e " ],
f o r m ["message _ h e l p "
v a l i d a t e Z I P C o d e ( f o r m [ " z i p c o d e " ] , f o r m [ " z i p c o d e _ h e l p " ] ) && v a l i d a t e N o n E m p t y ( f o r m [" d a t e " ],
f o r m [" d a t e _ h e l p " ))
&s
v a l i d a t e N o n E m p t y ( f o r m [" n a m e " ] , f o r m [ " n a m e _ h e l p " ] ) s& v a l i d a t e N o n E m p t y ( f o r m [ " p h o n e " ],
f o r m [" p h o n e ^ h e l p " ])
v a l i d a t e N o n E m p t y ( f o r m [ " e m a i l " ] , f o r m [" e m a i l _ h e l p " ])) // О т п р а в к а з а к а з а на с е р в е р
{
__
a l e r t ("Простите,
{
М е т о д 5иЬ т И () вы зы вает ся для о т п р а в к и данны х на сервер т олько при полож ит ельном р е з у л ь т а т е п р о в е р ки .
f o r m . s u b m i t (); else
SS
В о л ь ш у ю ч а с т ь т ел а ф у н кц и и з а н и м а е т _ больш ой о п е р а т о р ' if/e ls e , вы зы ваю щ ий ф у н к ц и ю п р о в е р ки для ка ж до го из полей ф ормы .
но ф о р м а з а п о л н е н а неверно")
в в о д н е к о р р е к т н ы х данны х яв л я е т с я д о с т а т о ч н о зн а ч и м о й п р о б л е м о й , чт обы о п р а в д а т ь появление всплы ваю щ его окна.
_
Чаапо
^аД аБ аеМ ы е
Bonj>oCbi Каким образом функция p l a c e O r d e r () управляет отправкой данных формы на сервер?
3 * Вы же говорили, что не стоит пользоваться всплывающими окнами при проверке данных...
; Оператор i f / e l s e в теле функции структурирован таким образом, что при обнаружении некорректных данных в любом из
В большинстве случаев это действительно так, потому что пользователю в результате приходится прервать процесс заполнения формы, чтобы прочитать сообщение и щелкнуть на кнопке ОК. Но щелчок на кнопке Order Banner осуществляется только после завершения ввода данных. И попытка отправить некорректно заполненную форму является достаточно веской причиной для появления всплывающего окна с предупреждением.
полей будет запущен оператор e l s e , вызывающий функцию
a l e r t ( ) . Если же проверка всех полей покажет корректность введенных данных, будет вызван метод s u b m i t () объекта fo r m , который и отправит данные на сервер. То есть отправка информации зависит от того, будет ли вызван метод
s u b m i t ( ) . Он является эквивалентом кнопки submit в языке HTML.
336
глава 7
S
формы и проверка данны х
Проверка Времени к сожалению, проверка корректности ввода индексов принесла Го варду только временное облегчение, потому что практически сразу он столкнулся с новой проблемой. Теперь он показал баннер в нужном месте, но в другой день, так как что-то произошло с введенной датой...
Enter thedate for the message to be shown: |05/1o/2008
Еще один не довольны й кл и е н т . далее ►
337
проблемы с датой
Проверка даты Говард понял, что недостаточно проверить, ввел ли пользователь дату, следует также удостовериться, что дата была введена кор ректно. Для этого нужно выбрать формат даты. Например, пусть сначала двумя цифрами обозначается месяц, потом двумя цифра ми — день и наконец четырьмя цифрами — год.
ММ/ДД/ГГГГ Месяц^ Как и день, одозначается двумя цифрами.
ф рагм ент ы . даты отделены друг о т друга косой чертой.
Пусть год обозначается ч е- м ы р ш я символами... мы же не х о т и м ст олкнут ься с п роб ле мой 3 0 0 0 года!
> Е м егІІ,еаа8Іі,,і|,ет.5м ;і.1о в,
I
Выбор формата даты — это самая простая часть задачи. Намного слож ней реализовать процедуру проверки на соответствие этому формату. Существуют функции, позволяющие разделить строку на части, исполь зовав в качестве разделителя какой-либо заранее выбранный символ, например косую черту. Н о такая задача слишком сложна. Ведь придется сначала поделить строку на фрагменты, а затем удостовериться, что каж дый фрагмент содержит только цифры и имеет заданную длину. Вот как эта процедура будет выглядеть пошагово:
©
О
А
Разобьем значение поля на набор строк, использовав в качестве разделителя косую черту.
"05"
Убедимся, что первая строка состоит из двух симво лов, и это — цифры.
"05"
Убедимся, что вторая строка состоит из двух симво лов, и это — цифры. Убедимся, что третья строка состоит из четырех сим волов, и это — цифры.
338
глава 7
символа сост ав л я ю т число... ОК.
"1 о " ф
символа, но эт о не число! "2008"
О
Проигнорируем все данные после второй черты.
с точки зрения написания кода такая последовательность выгля дит достаточно просто, но проверить повторяющийся несложный шаблон можно и еще более простым способом.
"2 0 0 8 " "1о"
__ Четыре символа сост авляю т число...
0
ОК.
-Н ет данных.
формы и проверка данны х
А вот если бы даты можно было прове рять без разделения на строки... Мечтать ведь не запрещено?
далее *
339
разве вы не слыш али этого выражения?
Регулярные выра)кения не «регулярны» в JavaScript имеется такой мощный инструмент, как регулярные выра жения, созданный специально для поиска в текстах совпадений с вы бранным шаблоном. В ы создаете шаблон и применяете его к строке, ища совпадение, точно так же, как в полиции проводят опознание подозревае мых... впрочем, вы работаете с более сговорчивыми объектами!
С ов падение!
Высокий, без очков, короткие волосы
Регулярные выражения используются для поиска совпадений в тексте. 340
глава 7
Ш аблон сост оит из п еречня ф и зи ч е ских ха р а кт е р и ст и к вн е ш н о ст и человека.
С
Шаблон описывает физические свойства, которые затем рассматриваются в приложении к реальным людям. Регуляр ные выражения позволяют делать то же самое со строками.
ф ормы и проверка данны х
Задание шаблона Если при опознании в полиции используют шаблон с перечнем физических характеристик внешности чело века, текстовые шаблоны включают в себя определен ную последовательность символов, например набор из пяти цифр подряд. Именно так выглядит американский индекс.
Шаблон
-у
Совпадение!
"37205"
" 5 2 80"
”А 3492"
"741265"
"0070В"
Слишком, много символов.
Содержит буквы.
К сожалению, превратить состояш,ий из пяти цифр индекс в регулярное выражение не так-то просто. Ведь для описания шаблонов используется компактный и на первый взгляд совер шенно непонятный синтаксис. Сразу и не догадаешься, что такое выражение означает всего лишь состоящий из пяти цифр индекс:
А ну тихо! Я пытаюсь разглядеть шаблон...
^
Шаблон представ ляет собой п о следовательность из пяти цифр.
Слиш ком ЛЛйЛО символов.
Содержит буквы.
= #####
Э т о т символ
обозначает начало входных данных.
, Цифровой символ должен повторяться S раз. ч/
Шаблон
/■ '\< Ц 5 }$ /
Все регулярные выражения начи-^_ наются и закан чиваются косой чертой.
Г Цифровой символ.
Э т о т си м во л
указывает на коней, ввода.
Н е волнуйтесь, если вам кажется, что в ы ничего не понимаете. М ы еще не раз будем возвращаться к этому шаблону.
далее ►
341
анализ регулярного выражения
Структура регулярного Выра}кения Регулярное выражение напоминает строковый литергш, но в от личие от последнего не заключается в кавычки или в апострофы, а начинается и заканчивается косой чертой (/ /).
Выраж ение
Регулярное выражение начинается с косой черты и заканчивается ею.
ш
Регулярные выражения располагаю т ся между абумя косыми черт ам и Тело регулярного выражения состоит из набора так называемых метасимволов, которые вместе с буквами и цифрами формируют лаконичный, но исчерпывающий щаблоп. Для создания рабочих шаблонов вовсе не обязательно знать все нюансы «языка». Доста точно запомнить самые распространенные метасимволы: э т о всего л и ш ь т о ч ка .
Обозначает любой символ, кроме перево да строки. \< 1
Обозначает любую цифру.
\ з
К т а ки м сим волам о т н о с я т с я п робелы , т а б у л я ц и я , зн а ки перевода с т р о к и и т . п.
Обозначает символы пробела.
, М н о ги е м е т асим волы начинаю т ся с обрат ной косой черт ы .
Перед э т и м с и м
Символ обозначает на волом м о ж е т р а с полагат ься т о л ь чало ввода данных. ко ко са я че р т а .
\w
Обозначает любой символ латинского алфавита.
Символ конца ввода данных.
М ы постарались дать как можно более исчерпывающие опи сания метасимволов, но их назначение станет еще более по нятным в процессе практического составления шаблонов...
342
глава 7
После эт о го си м во л а м о ж е т на хо ди т ься т о л ь ко косая че р т а.
ф ормы и проверка данны х
Метасимволы
/ \ w /
О д и н сим вол. о д н а буквл д а и А и н с ко г
аА ф лвы т а-
/\d/<e
О дна ц и ф р а в начале ст роки.
Л
Метасимволами называют ся символы, используемые для написания регулярных выражений.
О д н а циф ра.
в регулярных выражениях один символ можно обозначить разными способами. А как быть со строками из нескольких символов? Давайте посмотрим на примеры таких строк:
/cat$/ [буквосочет ание \ « c a t» в конце ст ро ки...нигд е не п о п а д а е т ся!
/\d /
"2 n ite "
Д б е циф р»!
в конце с т р о к и .^
"c a t c h 2 2 " /\d\d$/
" 007" Т р и циф ры подряд.
О дна ц и ф ра в начале ст роки.
1 ^ с ,з Х .1 \ " / d /
/\d\d\d/ '
нение
б у кв о с о ч е т а н и е « с а 1» о начале с т р о к и .
Напишите регулярное выражение для полного американского индекса, который имеет форму # # # # # - # # # # и должен появляться отдельно.
далее >
343
реш ение упражнения
-
Вот как выглядит регулярное выражение для полной формы американского индекса # # # # # - # # # # ,
•Р тЖ е н и е
решение
Э т о т си м во л ст авит ся в к о н -
Э т о т си м во л ст авит ся в и а чале с т р о к и .
ст роки. В конце регуляр но го в ы р а ж е н и я с т а в и т с я еще одна косая че р т а .
^
Р егулярное л вы р а ж е н и е — ^ начи н а е т ся с косой ч е р т ы Т а к о б о зн а ча ю т ся п я т ь ц и ф р подряд.
Д е ф и с в да н н о м с л у чае не и м е е т особого значения... О н всего ли ш ь р а зд е л яе т две ч а с т и индекса.
,Т а к о б о зн а ч а ю т ся ч е i^ b ip e ц и ф р ы подряд.
Количество повторений в регулярных выражениях любой текст, не относящийся к метасимволам, проверяется на совпадение. Это означает, например, что последовательность символов /howard/ совпадает с текстом «howard» в произвольной части строки. Кроме того, существуют метасимволы, задающие количество повто рений. И х называют квантификаторами.
Л П редш ест вую щ ий с и м в о л не обязат елен и м о ж е т п о являт ься Предшествующий символ должен совпасть пр о и зво льн о е число раз.
{Л }
Предшествующий шаблон должен появиться ровно п раз.
ноль или более раз.
Управляет числом п о явлений илаблона.
Предшествующий Предшествующий символ должен совпасть один или более раз.
с и м в о л обязат елен и м о ж е т появлят ь ся п роизвольное число раз.
П редш ест вую щ ий ------ —э л е м е н т не о бяза т е л ен , но п о я в и т ь с я м о ж е т т о л ь к о один
Предшествующий элемент может как при- Р‘^3. сутствовать, так и отсут ствовать.
344
глава 7
Т ехнически э т о не квант иф икат ор. С кобки и с п о л ь з у ю т с я для г р у п п и р о в к и о т дельны х сим волов.
о Группирует символы и (или) метасимволы
формы и проверка данны х
Повторение шаблона
Квантификаторы задают количество повторений шаблона.
Квантификаторы позволяют сделать регулярные выражения более краткими. Теперь вам не требуется в явном виде писать все символы, достаточно указать, сколько раз их следует по вторить. Вот как будет выглядеть шаблон для полной формы индекса после записи с использованием квантификаторов: К вант иф икат ор {} избавляет от н е обходимости писат ь все цифре?!. Метасимволы и квантификаторы позволяют создавать регуляр ные выражения для любых сочетаний, которые могут появлять ся в строках. / • + /
/ ( H o t ) ?
? D o n u ts /
/ \ у г * /
Совпадает с произвольны м количест вом а лф авит н оцифровых символов, оклнзчая п ус т ую ст року.
Любой сим вол должен появит ься один или более раз... совпадает с непуст ой строкой.
Совпадает с выражением « p o n u ts » или « H o t Ропиг$».
Укажите назначение перечисленных слева метасимволов и квантификаторов. Символ указывает на конец строки.
\w
Предшествуюш;ий символ обязателен и мо жет появиться произвольное число раз.
$
Означает любой алфавитноцифровой символ.
\с1
Означает любой символ, кроме пере носа строки.
-I-
Означает любую цифру.
*
Предшествующий символ не обязателен и может появиться произвольное число раз. далее ^
345
спросит е прямо сейчас
КТО Вот какое описание соответствует каждому из указанных в левом столбце метасимволов и квантификаторов. Символ указывает на конец строки. Предшествующий символ не обязателен и может появиться произвольное число раз. Означает любой алфавитноцифровой символ. Означает любой символ, кроме пере носа строки. Означает любую цифру. Предшествующий символ обязателен и мо жет появиться произвольное число раз.
_
Часщо
^аД аБ аеМ ы е Б о ц |э о с :ь 1
Регулярное выражение — это строка?
• Как найти в тексте знак доллара? ; Как и в случае со строками, в иауаЗспр! специальные символы выделяются обратными косыми чертами.
Q ; Немножко терпения. Скоро вы попрактикуетесь в применении регулярных выражений. Они
нужно написать символ $ как \ $ . Аналогичное правило действует для прочих специальных символов, например
действительно очень удобны для проверки данных сложных форматов, например дат или адреса элекгронной почты. В форме Bannerocity еще много нуждающихся в проверке полей, для части которых вам потребуются регулярные выражения.
Можно ли применять регулярные выражения к другим типам данных?
таких, к а к * и +. Все прочие символы помещаются в регулярное выражение в своем обычном виде, без всякого
А каким образом в JavaScript используются регулярные выражения?
0 ? Нет, регулярные выражения были созданы специально для поиска заданных шаблонов в текстовых строках. Но это не
дополнительного форматирования.
! Нет. Регулярное выражение можно считать описанием строки или ее части. Регулярные выражения тесно связаны со строками и ищут в них указанные пользователем текстовые шаблоны, но строками они при этом не являются.
умаляет значения данного инструмента, позволяющего искать в текстовых строках самые разные варианты шаблонов.
346
глава 7
Соответственно, для указания на знак доллара в регулярном выражении
Имеют ли регулярные выражения отношение к проверке данных? Ведь мы заговорили о них в теме про проверку ввода дат.
Ql
1\Лы дойдем и до этого, честное слово! Регулярные выражения в JavaScript представляются в виде объектов, снабженных набором необходимых для функционирования методов.
ф ормы и проверка данны х
М Л С Т Ё Р Ш Л Б1л«Й Ж В Интервью недели: З ага д о ч н ы е , но м о щ н ы е р егул яр н ы е в ы р аж ен и я
Head First:Я много слышал о вашей способно сти находить в тексте указанные шаблоны. Это действительно так?
Head First: Кажется, я понял, что вы имеете в виду. Шаблон — это описание текста, которое может появиться в строке, но не сам текст?
Регулярное выражение: Да, я своего рода рас-
Регулярное выражение: Именно так. Пред ставьте, что я прошу вас дать мне знать, когда пройдет человек, высокий, с короткими воло сами и без очков. Это же описание человека, а не он сам. Как только появится парень Ален, подходящий под это описание, м ы скажем, что шаблон совпал. Н о под описание могут попасть и другие люди. Без шаблонов м ы не смогли бы проверять, подходит ли человек под описание. Так что разница между методом in d e x O f () и мной в том, что он ищет Алена, а я высокого человека, с короткой стрижкой и без очков.
членитель кода, способный, взглянув на строку, сразу обнаружить нужный шаблон. Меня можно использовать даже в ЦРУ... Н о они не отвечают на мои звонки.
Head First:Хотите ловить шпионов? Регулярное выражение: Нет, я просто л ю блю отыскивать шаблоны. Дайте мне какие угодно параметры, и я тут же их найду, ну или, по крайней мере, сообшу, что совпадений не обнаружено. Head First:А разве метод i n d e x O f {) объекта S t r i n g не делает то же самое?
Регулярное выражение: Этот любитель даже не представляет, что такое работа с шаблонами. Нет, если вам нужен простейший механизм по иска, который, к примеру, ищет в строке слово « lam e», метод i n d e x O f () вам поможет. Н о в более серьезных случаях он бессилен, так как не умеет анализировать строки. Head First: Н о разве поиск по строкам не явля ется поиском шаблонов?
Регулярное выражение: Разумеется. Дойти до почтового ящика — это тоже физическое упражнение, но что-то его не включают в про грамму Олимпийских игр, по крайней мере пока. Так и обычный поиск. В ы ищете совпаде ния простейших шаблонов — статических слов или фраз. А теперь представьте, что требуется найти дату или адрес URL. Такие запросы хотя и имеют строковый формат, но не являются статическими.
Head First:А каким образом ваши способности могут применяться для проверки данных? Регулярное выражение: Такая проверка выполняется именно на соответствие опреде ленному, заранее заданному формату. Так что я беру шаблон и смотрю, подходит ли он к дан ным. Положительный результат означает, что данные введены корректно. Head First: Регулярных выражений должно быть очень много? Регулярное выражение: Конечно. И именно эта часть моей работы требует наибольшей сосредоточенности — написание регулярного выражения, описывающего очередной формат. Head First: Большое спасибо, что рассказали про вашу роль в проверке данных. Регулярное выражение: Нет проблем. Я при вык объяснять... Думаю, это мой поведенческий шаблон.
далее *
347
проверка при помощ и регулярны х выражений
Проверка данных при помо1ци регулярных Выраукений Давайте перестанем создавать регулярные выражения просто для того, чтобы посмотреть, как они работают, вернемся к полю для ввода дат на странице Bannerocity и поможем Говарду с заказа ми. В JavaScript регулярные выражения представлены объектом R e g E x p , который снабжен методом t e s t {). Именно этот метод и проверяет соответствие нужному нам шаблону.
Метод test() объекта RegExp проверяет наличие в строках заданного шаблона.
Э т о р е гуля р ное вы раж ение для индекса из п я т и циф р.
Д анны й лит ерал авт ом ат ически создает о б ъ е к т RegEx. ,В ка че ст ве ахр гум е нт а м е т о д и п е р е да е т ся з н а чение,, введенное в поле. var геаех = /^\d{5}$/;
if (!regex test{inputField.-value)) / Индекс
Если м е т о д te s t() в о звра щ ае т значение Ш 5 е , з н а ч и т , данные не п р о ш л и п р о в е р ку .
введен
V
неверно!
М е т о д te s to вы зы вает ся о б ъ е к т о м RegEx.
М е т о д te s t o в о звр а щ а е т значение tr u e п р и с о в п а дении с ш аблоном .
Метод t e s t () можно вызвать для каждой из функций проверки, но м ы предпочтем создать обобш;енную функцию на основе регу лярных выражений. Присвоим ей имя v a l i d a t e R e g E x (). Вот как выглядит принцип ее работы:
Проверяет, совпадают ли переданные ей в качестве аргументов шаблон и строка. При совпадении присваивает подсказке переданный ей в качестве аргумента текст и возвраш;ает f a l s e . validateRegEx(regex,
В случае несовпадения удаляет подсказку и возвраща ет значение t r u e .
Осталось только написать код этой функции. Большая его часть уже попадалась нам в составе других функций провер ки, чем м ы и воспользуемся.
348
глава 7
inputStr,
helpText,
help№ssage) ;
формы и проверка данны х
----------- --------- — ------
■ fu n c t i o n validateRegEx(regex, // п р о в е р и м к о р р е к т н о с т ь
// Д а н н ы е
некорректны,
if (helpText != null)
.{
r e t u r n false;
if
«»»е
h e lpMessage)
I
^
задал
^
helpText. i n n e r H T M L = helpMessage;
"Г /
hllpText,
д а н н ы х ^ ^ п р ^
(iregex.tes 0 . e g e x . t e stt((ii n ppuut St bt rt r)n)
if
'■ xnputStr,
В качестве а р г у м ент ов передаю т ся регулярны е вы ра жения, данные ввода, т екст и элем ент подсказки.
Н есоот вет ст вие условию означает некоррект ност ь дан ных, поэт ом у о т о бразим подсказку.
Регулярное выраже ние сравнивается с данными ввода.
» р р -» » “ '
(helpText
!= null)
helpText. i n n e r H T M L = r e t u r n true;
Если проверка пройдена, т е кс т подсказки исчезает.
)
Возьми в руку карандаш Напишите код функции v a l i d a t e D a t e ( ) , которая для проверки введенной в поле на странице Bannerocity даты использует функции v a l i d a t e N o n E m p t y ( ) и v a l i d a t e R e g E x ( ) . Подсказка: у этой функции два аргумента — данные ввода и элемент со вспомогатель ным текстом.
далее *
349
реш ение упражнения
Возьми В руку карандаш Решение
Вот как выглядит функция v a l i d a t e D a t e ( ) , которая для проверки введенной в поле на странице Bannerocity даты использует функции v a l i d a t e N o n E m p t y () и v a l i d a t e R e g E x ().
Сначала функция v a lid a t e N o n E m p t y ( )
проверяет , чт о поле не являет ся пуст ы м.
function validateD ate(jn^utFieid, helpText) { // Проверяем, введены ли данные в поле if (Jva(idateN onEm pty(inputFie!d, helpText))
Ф ун кц и и
регулярное — вы раж ение для дат ы .
/ / Проверяем, являю т ся ли эт и Эйнн\(е датой re tu rn va lid a teR eg E x (/'^\d iZ }V \d {Z }\/\d {4 -}$ /, inputField.vaiue, kelpText, ^
"Пожалуйста, Ь в е а и т ^ а т у (н априм ерТ ^^ЇТ Ч Л /І й 75)."); }
Так как косая черт а являет ся м ет а си м во лом , ее заклю ча ю т между обратными косыми черт ами.
Для задания выражения ф орм ат а М М / Д Д /Г Г Г Г использую т ся как м е т а с и м волы, т а к и квант иф икат оры .
А почему бы не допустить ввод года в виде только двух символов?
¥
И нт ересно, будут ли пользоват ься ваш им сценарием в Z 1 0 0 году?
Проблема 2100 года еще так далеко... Учитывая, что до следующего рубежа веков еще очень много времени, наверное, можно позволить пользователям вводить год в виде только двух цифр. Вряд ли какой-то из написанных в наши дни сценариев JavaScript проживет 90 лет и столкнется с пробле мой. Говард сначала хотел для надежности в Bannerocity вводить год в виде четырех символов, но потом решил, что, если его де тище и доживет до следующего века, тогда и можно будет внести в него исправления.
350
глава 7
формы и проверка данны х Часзцо З ад аваем ы е
вызывать функцию v a lid a t e N o n E m p t y () Бвнутри : Зачем функции v a l i d a t e D a t e () ? Разве регулярные
А что, если я хочу написать сценарий с учетом треї требований завтрашнего дня. Это сложно?
выражения не умеют работать с пустыми полями?
О
0:
; Да, регулярные выражения умеют проверять наличие
I Вовсе нет. Предвосхищение будущих требований и написание кода с их учетом обычно не является проблемой.
или отсутствие данных, поэтому упомянутую вами функцию можно удалить. Однако, проверяя, были ли введены данные, и отображая соответствующий вспомогательный текст, мы
В случае с Bannerocity мы учтем будущие требования, оставив ввод года в виде четырех символов. Профессиональные программисты позволяют пользователям вводить только две
делаем страницу интуитивно понятной для пользователей. Отсутствие данных и ввод некоррекгных данных должны
последние цифры, добавляя первые две в тексте сценария. В результате данные, вводимые в форму, все равно будут храниться в виде четырех цифр.
сопровождаться разными подсказками. Именно на этом принципе работает наша система помощи, позволяющая пользователю понять, как именно следует заполнять форму. И ради этого маленького усовершенствования можно написать несколько дополнительных строчек кода.
Диапазон Вхо}кдений Квантификатор {} используется для указания коли чества появлений шаблона в строке. О н может запи сываться и в другой форме, уже с двумя аргументами, определяющими минимально и максимально возможное количество повторений шаблона. Это дает еще один до полнительный инструмент настройки:
{ m i n ^ т а х ]
Предшествующий шаблон должен появиться как ми нимум min раз подряд, но не больше, чем max раз.
ММ/ДД/ГГГГ — не единствен )у д ь те I ный возмож 0 СІЦ 0|> 0 Ж Н ь і! ный формат дат. В ряде стран более привыч ным является указание дня, а только затем месяца, то есть запись производится в форма те ДД/ММ/ГГГГ
У казы вает ^ с ко л ько р а з ш аблон м о ж е т п о я ви т ься как м и н и м у м и как м а к сим ум -
Некоторые пароли позволяю т вво дит ь от пят и до восьми буквенноцифровых сим волов, чт о за м еча т ельно описывается при помощ и коант иф икат ора {}.
возьми в руку карандаш Перепишите регулярное выражение из функции v a l i d a t e D a t e () таким образом, чтобы оно позволяло ввод года как в виде двух, так и в виде четырех цифр.
далее ►
351
реш ение упражнения
Возьми в руку карандаш '^ о т о ш л а
бШсНИб
выглядит регулярное выражение из функции v a l i d a t e D a t e ( ) , позволяющее вводить год как в виде двух, так и в виде четырех цифр.
В т аком виде квант иф икат ор {} задает миним альное и М аксимальное к о личест во циф р при оводе года.
То есть получается, что код провер ки позволяет вводить год тремя цифра ми? Это же лишено смысла... КЛЮ ЧЕВЫЕ МОМЕНТЫ
Регулярное выражение для даты дейст вит ельно ПО ~ зволяет ввест и в конце т олько т ри цифры! Ente the date for the message to be shown; [03/01/200
Регулярное выражение совмещает шаблон с тек стом строки. L Кроме обычного текста в регулярных выражениях используются метасимво
Никакие ревизионисты не помогут вернуть JavaScгipt во времена до десятого века. Соответственно, нам нет ника кого смысла поддерживать ввод года в виде трех цифр. Убрав эту возможность, вы уменьшите коли чество потенциальных проблем в бизнесе Говарда.
лы и квантификаторы. В JavaScript регулярные выражения поддержива ются объектом R e g E x p , но обычно создаются в виде литералов. Метод t e s t {) объек та R e g E x p проверяет заданный регулярным вы ражением шаблон на соот ветствие строке текста.
352
глава 7
формы и проверка данны х
Выбери это... или т о Другим полезным метасимволом для построения регулярных выражений является перечисление. П о своему виду и функциональности перечисление напоминает оператор ИЛИ. Но, в отличие от этого оператора, для записи перечисления используется всего одна вертикальная черта |,разделяющая допустимые варианты. Другими словами, шаблон считается совпавшим при соответствии одному из двух указанных выражений.
это\ то Шаблон совпадает при совпадении с одним из указанных вариантов.
М ет асим вол перечисления позволяет реализовы ват ь выбор из двух альт ернат ив.
/ s m a l l I m e d ii im | l a r g e /
/ ( r e d Ib lu e )
p ill/
Это выражение совпадает как со 'ст р о ко й « re d рЩ», т ак и со ст рокой «blue pill».
Волге сложные вариант ы выбора реализую т ся при помощ и набора перечислений.
далее *
353
это действительно ваш номер?
Возьми в руку карандаш. IX 'ешение
Вот как выглядит регулярное выражение из функции v a l i d a t e D a t e ( ) , совпадающее только со строками из двух или четы рех символов.
М ет асим вол перечисления ( ) задает шаблон для ввода года как 6 виде двух, т ак и в виде чет ы рех цифр.
Никаких случайностей Говарду очень понравился новый, надежный способ проверки дат, обеспечивающий точное следование заданному шаблону. И он решил воспользоваться регулярными выражениями для проверки корректности ввода данных и в двух оставшихся полях формы Bannerocity: номер телефона и адрес электронной почты. прекрасно... но gantïerocity - P ersonateed Online S ^ S w n e f ^
# 0 в
я хочу большего!
b a n n e r o c i t y
^Vlandariga .. MecTa
Enter th e b an n er m essag e:
Enter ZIP co d e of the tocatton: jl 0012
Mano!
________ __
Enter th e d ate for th e m ess a g e to b e show n: j 03/11 /200 ' » « « « Enter youf nam e; j Enter your phone nym ber;
j
___ _________ _____
Enter your em ail ad d ress; j Order Banner Done
Вводимые пользоват елям и даты т еперь проверяю т ся при п о м о ици регулярны х выражений, чт о обеспечивает ст рогое следование ф орм ат у.
Идея Говарда о необходимости проверки вводимых телефонов и адресов электронной почты вполне здравая, но для ее реали зации нам потребуются новые регулярные выражения.
354
глава 7
m/14/1976}
^
1
ф ормы и проверка данны х
Вы меня слышите? Проверить корректность ввода телефонных номеров достаточно просто, так как они записываются в достаточно строгом формате. Разумеется, без регулярных выражений нам пришлось бы стол кнуться с необходимостью деления строк, но нам этого делать не придется. Американские телефонные номера строятся по следую щему шаблону:
Шаблон
= # # # -# # # -# # # #
Так как Говард не со бирается предлагат ь свои услуги ииост ран■цам . можно ограничит ься ам ериканским ф орм ат ом т елеф онны х номеров.
Заменим дефисы косыми чертами и укажем, из скольких цифр состоит каждый фрагмент. Получившееся регуляр ное выражение имеет практически такой же формат, как и в предыдущем случае. Шаблон для даты был создан при помощ и м е т асим вола \с1 и кван т иф икат ора {},
Шаблон для номера т елеф она от личает ся от шаблона для даты наличием дефисов, разделяюи^их группы цифр. Благодаря регулярным выражениям и функции validateRegEx () написать код функции validatePhone (), проверяющей номер телефона, несложно. function validatePhone(inputField, // Проверяем,
helpText)
{
бьши ли введены данные
if (!validateNonEmpty(inputField,
helpText))
return false;
// Проверяем,
являются ли данные номером телефона
return validateRegEx(/''\d{3}-\d{3)-\d{4}$/, inputField.vaiue,
helpText,
"Пожалуйста, введите номер телефона
(например,
123-456-7890).");
далее >
355
это .сот или .огд?
Вам письмо Теперь, когда функция проверки номера телефона готова, у Говарда осталась только одна забота. Проверить коррект ность ввода адресов электронной почты в форму Bannerocity. Как и раньше, м ы начнем решение этой задачи с написания регулярного выражения.
Шаблон
Zj 3 или 4 а лф а ви т н о цифровых символа.
LocalName^DomainPrefix.DomainSuffix ....
Все выглядит не так уж страшно — адрес электронной почты представляет собой всего лишь три текстовых фрагмента, которые могут быть составлены из букв латинского алфавита и цифр, а также символа (0) и набора точек.
_ Здесь могут бстрецаться как буквы, т ак и цифры. Все эт и адреса подходят под шаблон. Значит , дело сд&Айно... или вce~^л^aкы неилр
howard0bannerocity.com sales@duncansdonuts.
puzzler0youcube.са Создание шаблона для адреса электронной почты является не сложным процессом.
А дрес должен начинаться Ч/ с одного или нескольких /^ \w + (i\w + \ буквенно-циф ровы х с и м \ •\ волов.
Шаблон кажется вполне рабочим. Оста лось понять, всегда ли адреса электрон ной почты записываются именно в таком формате.
2 г
}
Так как точка входит в число . специальных сим волов, ее следует п о м ест и т ь между обрат ными косыми черт ам и.
41Й/ / /у/
•После символа @ появляет ся еще один или несколько буквенно-циф ровы х сим во лов.
В конце адреса элект ронной почт ы должны ст оят ь 2., 3 или 4 а лф а ви т н о цифровых символа.
Ш ТУРМ Возможны ли другие варианты шаблона для адреса электронной почты? Вспомни те, какие еще адреса вы видели.
356
глава 7
ф ормы и проверка данны х
исключение — это праВило Адреса электронной почты более сложны, чем это кажется на первый взгляд. При написании нами шаблона необходимо учесть существование других вариантов написания адреса электронной почты. Вот примеры совершенно корректных адресов:
cube
lovers@youc\3be aviator.howard0bannerocity.com
Подчеркивание в имени по ст о во го ящика.
}
\_ Т о ч к а в имени п о чтового ящика.
i-love-donuts@duncansdonuts.com Дефмс в до мгнном имени.
Четыре символа о имени домена первого уровня. ------------- X
.
Для проверки адресов электронной почты нам по требуются дополнительные символы.
Д еф исы в имени почтового ящика.
seth+jason0mandamд о . u s
Знак ь в имени почтового ящика. гтдЬу0 уоисиЬе.сот.nz т я т т ш я ш т т т ш т т г /ftw
Многоуровневое . доменное имя.
Что б ы описать все многообразие адресов электронной почты, нам не хватает символов. Изначально м ы считали, что фрагменты адреса электронной почты записываются только буквами и цифрами. Теперь в ша блон требуется вставить дополнительные символы...
далее ►
357
выбор символа
Дополнительные символы Еще одной функцией, которая непосредственно касается спо соба написания шаблонов для адресов электронной почты, яв ляются символьные классы. Именно они позволяют задавать правила вставки дополнительных символов. Символьный класс можно представить в виде набора правил для представления одного символа. к г [ C h a r a c t e r C l a s s ]
Символьный класс — это набор правил для задания определенного символа.
Символьные классы заклю чаю т ся в к ва дратные скобки.
Символьные классы позволяют вставлять в шаблоны для регулярных выражений дополнительные символы.
Выбор подходящего символа осуществляется среди набо ра, указанного в квадратных скобках. Рассмотрим несколь ко примеров:
/сі[іи]
д/
" с і і д " С шаблоном совпадают обе ст роки.
"сіид" " $ 3 .50 " "$ 5 " Под шаблон подходят все эт и ст роки.
)у д ь т е
" $ 19 .95"
Символьные классы — это именно то, чего нам не хватало для приведения в порядок шаблона записи адресов электронной почты.
358
глава 7
Не забывайте про знаки перехода.
Если вам требуется включить в выражение символ, совпадающий с метасимволом, ставьте перед ним обратную косую черту. Такой чертой (\), в частности, предваряются сим волы: [ \ ^ $ . I ?*-ь {).
ооцорожны !
формы и проверка данны х
Проверка адреса электронной почты Теперь м ы можем написать корректный шаблон для адресов элек тронной почты, который будет учитывать все возможные варианты написания имени почтового яш;ика и доменных имен.
Шаблон
ф р а гм ент может появит 1?ся один или не сколько раз.
LocalNameQDomainPrefix.DomainSuffix Любые буквы, цифры и с и м вол ~.
Любые буквы, цифры, а также символы
Точка счит ает ся част ью имени домена первого уровня.
Любые Z , 3 или 4 буквенно-цифровых сим вола, кот оры м предш ест вует точка.
Помните, что любой шаблон может быть создан несколькими способа ми. Это относится и к шаблону для адресов электронной почты. Ведь так сложно учесть все нюансы указанного формата данных. Впрочем, вы уже получили навыки конструирования шаблонов и убедились, насколько про сто они преобразовываются в регулярные выражения.
Возьми в руку карандаш_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Закончите код функции v a l i d a t e E m a i l ( ) , предназначенной для проверки корректности ввода адресов электронной почты. function validateEmail(inputField, //
if
Проверяем,
были
ли
введены
(!
helpText)
{
данные,
(inputField, helpText))
return false;
//
Проверяем,
являются
ли
данные
return validateRegEx(
адресом
электронной
почты
.......................................
,
inputField.vaiue, helpText, ); }
далее >
359
реш ение упражнения
Возьми Вруку карандаш Решение function //
Вот как выглядит функция validateEmail (), проверяющая корректность ввода адресов электронной почты.
validateEmail(inputField,
Проверяем,
были
ли
введены
helpText)
{
данные helpText))
return
//
false;
Проверяем,
'^turn
1
продолж аем проверят ь о т сцт ст вие данных при помощ и ф ункции validateN onEm ptyO -
являются
ли
данные
адресом
Шаблон для проверки адреса элект ронной почт ы был со ст авлен с прим енением боль ш инст ва м ет одов, которые мы изучали в эт ой главе.
электронной
validateRegEx (
inputField.vaiue,
helpText,
.Й9!У}!^.\ Имя почтового ящика м о ж е т сост оят ь из букв, цифр, т аких символов, как ., , и и должно ст оят ь в начале ст роки.
Д ом енное им я первого уровня мож ет сост о’ я т ь как из Я, т ак и из 4 символов.
(наприм ер, Johndoe@ acme.com)."
Если провеюка не будет пройдена, -появит ся вспом огат ельное со общение с образцом коррект ного адреса элект ронной почты.
Наде)кная форма Благодаря усилиям, направленным на проверку вводи мых в форму Bannerocity данных, заказы обрабатывают ся без проблем. Говард так счастлив, что по собствен ной инициативе показал вот такой баннер. Говард с вост оргом возвращ ает ся к л ю бим ом у занят ию ~ полет ам !
Enter the banner m essage: jl^ n d a n g o ... м еста д л я Enter ZIP code of the tocatton; |10012 Enter the date tor the m essage to be shown: [03/11/21
Вводимые номера т елеф онов и адреса элект ронной почт ы т еперь п р о ве ряю т ся на соот вет ст вие заданному ф о р м а т у данных.
Enter your name: jS eth Tinselnnan Enter yoyr phone numtier: |2 1 2 ) 555-5339 « e a s e enter a phone number (tor example, f 23-455-7890), Enter your emalt address: jseth t@ m an d an g o
rte e se enter an emeit address (for example, phmSo@Qecrm.oom). Order Banner i
360
глава 7
ф ормы и проверка данны х
Вкладка Согните страницу по вертикали, чтобы совместить два мозга и решить задачу. /
Зачем Іауа8сгір1 веб-формам? хо|>оШ о, а ДБа лучше!
<г-
«Mandango...выбор мест в кино для настоящих нуткчлн! > 105012 03/11/200 212-555-5339 setht@mandango
/ ' " v a l ( l e y 1u e I k r i e ) /
«...места для мачо!» 100012
March 11, 2009 (212) 555-5339 seth%t0mandango.us
/n a m e I i d $ /
JavaScript может так много нрерожить веб-формам, что сложно даже выбрать что-то одно. Ответ на вопрос в заголовке почти всегда включает в себя какой-то уровень данных. Но как они используются?
Управление
а й р а н и Ц а М и
Управление HTML с DOM
Управлениесодержимым веб-страницы при помощи JavaScript напоминает приготовление еды. Конечно, это не настолько грязное занятие... И, увы, вы не сможете съесть результат своих трудов. Тем не ме нее вы получаете полный доступ и Hr/WL-ингредиентам, из которых состоит веб-страница, и, что еще важнее, вы можете менять исходный рецепт. Ведь JavaScript дает возможность управлять HTML-кодом веб-страницы, что открывает для вас целый ряд интереснейших перспектив, которые реализуют ся посредством набора стандартных объектов DOM.
%
преобразование интерфейса
Функциональный, но неудобный Сценарий «Приключений нарисованного человечка» из главы 4 является хорошим примером интерактивной страницы, полу ченной при помощи JavaScript, но пользовательский интерфейс немного неудобен, особенно с точки зрения современных стандар тов. Всплываюш,ие окна с навигацией быстро начинают надоедать, а понять назначение кнопок перехода невозможно, потому что они помечены как 1 и 2.
Всплывающие окна м огут вызвать раздражение и даже прервать работку приложения.
Your journey begins at a fork in the road.
©00
«Приключения» ра ботают прекрасно... но могло быть и лучше.
Stick Fig ure Arfvem ure
VJelcOKG "to
STICK f m e Clickeitlner b u tto M "t®
Sbri.. Please choose; Л У
Из названий кнопок перехода совершенно н е понят но, куда они при оедут.
Элли решает поработать над интерфейсом своего приложения...
364
глава 8
управление страницами
Без Всплывающих окон Всплывающие окна с описанием сцены плохи еще и тем, что текст исчезает после щелчка на кнопке ОК. Лучше поме стить описание непосредственно на страницу. Вот как после у этого будут выглядеть «Приключения»:
Нобый набор ф айлов для «При клю чений нарисованного человеч ка» дост упен по адресу Ш р ://ш ш ш h ea d fm tia b s.c o m /b o o ks/kfjs/.
куда мне это помест ит ь?
Тег div Чтобы отобразить на странице описание сцены, сначала нужно выделить под него область страницы в виде H T M L -элемента. Так как описание появляется в виде отдельного параграфа, за дача решается при помощи тега <div>.
Тег и м еет а т р и б ут (Р. уникальны м об разом задающий элемент, в кот ором буда,т располагат ься т екст описания
< body >
text-au g,:,en ter..>
Please choose:
^decisioni" Value="l" „ Дает Л И атрибут ID тега <div> _______ ___ _____ ________^ доступ к описанию сцены?
,■ "'^^^^'^-''changeScened) " /> f2 " value="2" onoHov .. ^ J oncJ.iok= ChangeScene (2)" />
-v_
Именно при помощи атрибута 1В осуществляется доступ к элементам страницы, в том числе и к описанию сцены. И именно атрибут 1с1тега <div> даст кoдyJavaScгipt доступ к описанию. Кстати, подобную операцию вы уже проделы вали...
ь
i|
)удыпе оСЩо|>оЖНь1
Идентификаторы должны быть уникальными. Не забудьте, что атрибут
1с1предназначен для уникаль ной идентификации элементов страницы.
366
глава 8
управление страницами
Д оступ к HTML-эАементам с методом g e t E l e m e n t B y l d
() стандартного объекта d o c u m e n t м ы уже не раз сталкивались. Именно он дает до ступ к H T M L -элементам страницы... Пр и условии наличия у них уникального ID.
Это должно совпадать .с ат р и б ут о м id э л е м ент а HTML, в наш ем случае т ега div.
v a r sceneDesc = d o c u m e n t.g e tE le m e n tB y ld C 's c e n e te x t" )
\
Д о с т у п к элем ент у div o c y щ ест вляет ся при помош,и его ат риб ут а id. Имея в руках элемент с описанием сцены, м ы можем управ лять его содержимым. Н о сначала познакомимся с методом g e tE le m e n ts B y T a g N a m e (), коллекционирующим все элементы страницы с определенным тегом, например d i v или img, и помещающим их в массив в порядке появления на странице. . Имя т ега, без <>■
Г v a r d iv s = docum ent.getElem entsB yTagN am e("div");
Напишите код JavaScript, предоставляющий доступ к оранжевому изобра
йражнение
^йражн
жению. Сначала при помощи метода g e t E l e m e n t B y l d (), а затем — при помощи метода g e tE le m e n ts B y T a g N a m e () .
<body> <р>Выберите уровень сложности приключений;</р> <img id="green" src="green.png" alt="Расслабленный" / x b r /> <img id="blue" sro="blue.png" а1Ъ="Раздражающий" / x b r /> <img id="yellow" src="yellow.png" а11="Изматывающий" / x b r /> <lmg id="orange" src="orange .png" а11="Пугающий" / x b r /> <img id="red" src="red.png" а11="Суыасшедший" /> </body>
Методом g e t E l e m e n t B y l d {):, Методом g e tE le m e n ts B y T a g N a m e ():, далее ►
367
решение упражнения
Вот как выглядят варианты кода иауаЗспр!, предоставляющие доступ к оранжевому изображению.
нение ]''ешение
<body> <p>Before starting, please choose an adventure stress level:</p> <img id="green" src="green.png" alt="Relaxing" / x b r /> <img ld="blue" src=”blue-png" alt="Irritating" / x b r /> <img id="yellow" src="yellow.png" alt="Frazzled" / x b r /> __ i d = " o r a n g e " s r c = " ' o r a n g e . p n g " a l t = " P a n l c ked^^~~7?y
Оранжевое изображе ние являет ся чет верт ы м элем ент ом массива, поэт ом у его индекс 3.
r />
<img id="red" src="red.png" alt="Maddening" /> </body>
Методом g e t E l e m e n t B y l d ( ) : ...... 4^f:'^jC (^.^nt.^etElem entByld[''oranQ e'')_ Методом g e tE le m e n tsB y T a g N a m e ( ) : ......
Внутренний код элемента Под доступом к элементу H T M L подразумевается доступ к со держащейся в нем информации. В случае H T M L -элементов, содержащих текст, таких как d i v и р, это осуществляется при помощи свойства innerHTML.
Вы стоите в лесу.
Свойство innerHTML дает доступ к содержимому элементов.
один <р id = " s to r y " > Вы стоите <strong>oflMH</at;rong> в л е с у ,
О т ф орм ат ированное содержимое также __ хранит ся в свойстве
</р>
innerHTML.
J
Г d o c u m e n t.g e tE le m e n tB y ld C 's to ry " ) .innerHTML -<r-
368
глава 8
, С во й ст во innerH TM L
им еет дост уп ко всему содерж имому элем ент а, включая теги.
управление страницами
Создается впечатление, что можно не только легко прочитать содержимое НТМи-элемента, но и за писать туда новые данные.
Свойство innerHTML применяется и для задания содержимого страницы. Ведь оно позволяет осуществлять не только чтение, но и запись информации. Достаточно назначить этому свойству строку текста, и содержимое контейнера элемента будет заменено новым.
d o c u m e n t.g e tE le m e n tB y ld ( " s to ry " ) . innerHTML "Вы <strong>H6</strong> один!";
Содержимое э л е м е н т а за дается UAU, как 6 данном САЦчае. зам ещ ает ся п у т е м назначения ст роки свойству innerHTML.
Вы н е один! т ш яш ш
решение упражнения
Возьми в руку карандаш Решение Атрибут IP
Вот как выглядит код, присваивающий текст элементу, содержащему описание сцены, написанный при помощи свойства innerHTML.
т е га <aiv> с
сообщением — эт о "sceneText". in n e r Н Т М L - message
Непрерывное «приключение» Динамическое изменение описания сцен делает интер фейс «Приключений» более удобным и плавным. Ведь теперь вам не придется отвлекаться на всплывающие окна. Stick f igure Adventure
Такие небольшие переме ны, но мне они нравятся!
Т еперь описание сцены м е н я ет с я п р и переходе на о р у гу ю ст раницу
Youаюstandingon*е bridgeoveriookingарешжЛ! steam. Hcasechoose: _ lj _iJ
Теперь, когда при помощи тега < d iv > вы поменяли местоположение описания и задали значение свойства innerHTML, осталось добавить к «Приключениям» переменную m e s s a g e и в каждой из сцен присво ить ей нужное значение...
370
глава 8
управление страницами
У оДробНо ripo Код «]|]= Ч 1КЛ 1о Ч е Н и й »
< h tm l> <head> < title> npH K nra4eH M H
нарисованного
< sc rip t ty p e = "te x t/ja v a sc rip t"> //В к а ч е с т в е текущ ей выбираем var
cu rS cen e
4 e n O B 0 4 K a< /title>
сцену
fu n c tio n c h an g e S c e n e (d ec isio n ) / / У даляем о п и сан и е сцены
{
var message = sw itch
(cu rS cen e)
case 0: cu rS cen e
О (В вед ени е)
= 0;
Л окальная перелленная message будет хранит ь описание каждой новой сцены.
Переменной message присваивает ся т екст с описанием т екущ ей сцены.
{
= 1;
message = "yoar journey begins at a fork in the road."; break; case 1: if
(d e c isio n cu rS cen e
==
1)
{
= 2
message * "Tou have arrived at a cute little house in the woods.";
xo
are standing on the br dge overlooking a peaceful stream.'
/ / О бновляем и зображ ен ие сцены d o c u m e n t.g e tE le m e n tB y ld C 's c e n e im g " ) .s r c
= "scene"
+ cu rS cen e
// Обновляем описание сцены document.getElementByld("scenetext").innerHTMb = message; < /sc rip t> < /h ead >
Текст описания при ■ сваивается п е р е ' менной message при помощ и свойства
innerHTML.
<body> < d iv s ty le = " m a rg in -to p :lO O p x ; t e x t - a l i g n : c e n te r " > < im g i d = " s c e n e i m g " s r c = " s c e n e O .p n g " a l t = " S t i c k F i g u r e < d iv
+ ".p n g ";
id = " sc en e te x t"> < /d iv x b r
P le a se < in p u t < in p u t
A d v en tu re"
/x b r
/>
o n c lic k = " c h a n g e S c e n e (1)" o n c lic k = " c h a n g e S c e n e (2)"
/> />
/>
choose: ty p e = "b u tto n ” id = " d e c isio n l" ty p e = "b u tto n " id = " d e c isio n 2 "
v alu e = "l" v a lu e = "2 "
< /d iv > < /body> < /h tm l>
далее >
371
спроси прямо сейчас _
Часщ о
^адаБаеМые Bonj=>oc;j,i Предоставляет ли метод
Позволяет ли свойство
g e t E l e m e n t B y l d O доступ
innerHTML задавать значение любых
к элементам страницы?
HTML-элементов?
Q ; Да, но только при условии уникального
! Нет. Ведь далеко не все HTMLэлементы имеют какое-то значение.
значения атрибута i d . Именно этот атрибут делает возможным применение метода
g e tE le m e n tB y ld ().
Поэтому свойство innerHTML. применяется только для задания значений таких элементов, как d iv , и прочих контейнеров.
s p an , р
Что просиходит со значением, когда оно задается свойством innerHTML? ! Свойство innerHTML полностью переписывает предыдущее значение атрибута. То есть вы не можете добавить значение в innerHTML. Хотя можно осуществить соединение старого и нового значений и уже затем назначить его при помощи свойства
innerHTML.
Это может выглядеть, например, так:
e le m .in n e rH T M L += " Это п р ед лож ен и е п р и б а в л я е т с я .
Я слышала, что свойство innerHTML не входит в стандарт. Это правда?
N.
1 )
Да. Н о почему нас д о л ж н ы заботить стандарты? Свойство innerHTML изначально было создано Microsoft как функция браузера Internet Explorer. Постепенно с ним научились работать и другие браузеры, и свойство стало неофициальным стандартом быстрого и удобного изме нения значений веб-элементов. Н о факт остается фактом, в стандарт innerHTML не входит. А ведь стандарты позволяют унифицировать при ложения, заставляя их работать с как можно большим ко личеством браузеров. Кроме того, существуют стандарт ные способы решения ряда задач, более гибкие и более мощные, хотя и не всегда простые. М ы говорим сейчас о D O M , или объектной модели документа (Document Object Model). Именно так называется набор объектов, позволяющий JavaScript полностью контролировать структуру и содержимое веб-страниц.
372
глава 8
управление страницами
Объектная модель документа (РО М ) Объектная модель документа предлагает удобный с точки зрения сценария взгляд на структуру и содержимое веб-страниц, благодаря которому возмож Да, эт о дерево ыМее т ст ранный вид, но но их динамическое редактирование средствами JavaScript. В D O M стра именно т ак принят о ницы представляются в виде иерархического дерева элементов. Каждый предст авлят ь надор^ листок этого дерева называется узлом и непосредственно связан с каким-то узлов, ф opмupyн^m ^* элементом страницы. Узлы, расположенные снизу, считаются дочерними страницупо отношению к вышестояш;им.
<html> <headX/head>
<body> <р id=" story" > вы стоите < s t r o n g > o « H H < / s t r o n g > в лесу
</р> </body> </html>
DOM «видит» стра ницу как иерархию узлов. Пробелы, окружающие т ег <р> на ст ранице, и н т ер п р ет ирую т ся как пуст ой т екст .
Выделенный жирным т екст «один» располо жен под узло м т ега <strong>.
далее *
373
классификация узлов
Страница как набор узлов в модели D O M существуют различные типы узлов. Основные типы соответствуют структурной части страницы и главным образом состоят из узлов element и text.
document
Узлы DOM классифицируются в соответствии с их типом.
ELEMENT
Самый верхний узел дерева, представляющий собствен но документ и стоящий над элементом html.
Любой H T M L -элемент, соответ ствующий H T M L -тегу.
ATTRIBUTE
TEXT
Атрибут элемента. В иерархическом дереве не фигурирует, но досту пен через узел element.
Текстовое значение элемента, всегда храня щееся в дочернем для узла element-узле.
DOCUMENT
Указав типы узлов в иерархическом дереве, вы сможете понять, каким образом в объектной модели представлен каждый фраг мент страницы. В частности, обратите внимание на то, что узлы TEXT всегда располагаются сразу под узлами ELEMENT как часть их содержимого (или содержимое целиком).
Document
i
E LE M E N T
<html>
html
<headx/head>
<ьобу>
^
Хот я в РОМ сущ ест вует дост уп к а т р и б ут а м и им^ соо т вет ст вует отдельный т и п узлов, в составе дерева они не появляю т ся.
ELEM ENT elem ent
7
body
E LE M E N T
head
Вн соите <strong>o«™</stro„3> а лесу. </р>
J
</body>
TEXT TEXT
TEX T
"Вы стоите"
ELEM ENT
Jl
strongl
TEX T
'один"
374
глава 8
"b лесу."
8 данном случае элем ент head являет ся пуст ы м , но обычно под ним р а сп о лагаю т ся дочерние узлы.
управление страницами
далее *
375
реш ение упражнения
-|^ з ь м и в руку карандаш Решение
Вот как выглядит дерево иерархии узлов для показан ного ниже кода.
</head>
<body>
tevt
Г
Т
—
s.«
<dxv ^d=..scenetexf></di.xb, /> Please choose:
DOCUMENT S<input type="button" ld=..decislonr' v a l u e - l " о
<
W
,■
^ ^‘^^^'=''“"=hangeScene(ll " tvpe=..b„tton.. id-..decisio„2.. val„e=..2~ on . ■ .
</div>^\^
/>
D ocum ent
°"=li=''-'t:hangescene(2)" /> element
j
html
Пробелы, предш ест вую щ ие элем ент у и следующие за ним . и н т е р п р е т и р у ю т ся как пуст ы е элем ент ы т ипа text.
head ELEMENT
r
TEXT
im g g
1,^ I —
I
- J ГЕХТ
уг
TEXT
TEXT ELEMENT
376
I
ELEMENT
глава 8
elem ent elem ent
E ^ M ^ t te x t
управление страницами
CBoucmBa узлоВ в большинстве случаев работа с D O M начинается с объекта d o c u m e n t, который располагается на самом верху иерархического дерева. Этот объект имеет такие методы, как g e t E l e m e n t B y l d () и g e tE le m e n ts B y T a g N a m e (), а также набор свойств. Доступ ко мно гим из этих свойств возможен из любого узла дерева. Некоторые из объектов допускают перемеш;ения к другим узлам. То есть свойства узлов позволяют двигаться по их дереву.
Свойства узлов позволяют перемещаться по дереву DOM
nodeТуре
пос1еУа1ие Значения хранятся в текстовых узлах и узлах атрибутов, но не в узлах элементов.
Тип узла, например DOCUMENT или TEXT, вы раженный числом.
сЫ1сШос1ез
firstChild
lastChild
Массив, содержаш;ий перечень всех дочерних узлов в порядке их появления в коде страницы.
Первый дочерний узел.
Последний дочер ний узел.
Эти свойства дают возможность перемеш;аться по иерархическому дереву и получать доступ к данным отдельных узлов. Например, для быстрого выделения нужного узла достаточно воспользоваться его свойствами и методом g e t E l e m e n t B y l d (). a l e r t ( d o c u m e n t . g e tE le m e n tB y ld (" s c e n e t e x t " ) .n o d e V a lu e ); Свойство nodeValue Ъает дост уп к хранящ емуся в узле т екст у.
Свойство nodeValue содержит т олько неф ормат ированны й т екст . Т екст описания сцены в «П риклю чении» и з начально пуст ой.
Наверное, м ы выбрали для демонстрации не лучший пример, ведь в исходной сцене «Приключений» тег d i v не содержит текста. Н о уже для следуюш;их сцен появится текст с описанием, и ситуация будет выглядеть намного лучше.
ажнение
Вот код одного из узлов дерева со страницы 376. Рассмотрите его внимательно и укажите, какие узлы в нем упоминаются.
document.getElementsByTagName("body")[0].childNodes[1].lastChild
далее >
377
реш ение упражнения
нение
Вот какие узлы нашего иерархического дерева упоминаются в показанной ниже строчке кода.
------' Г dociiment.getElementsByTagName("body")[0].childNodes[1].lastChild .
У
Последним дочерним узло м главного э л е м ент а div являет ся элем ент с пуст ы м т екст ом .
М етод getE lem entsB yldQ возвращ ает элем ент с определенным IP-
Ч асто
Ч аД аБ аеМ ы е
М ет од в^^^^степЬвВуТадЫатеО позволяет получит ь все элем ент ы с определенным т егом , наприм ер с т егом <lnput>.
БоЦроСЬ! В чем разница между методами g e t E l e m e n t B y l d () и g e tE le m e n tsB y T a g N a m e () при работе с деревом DOM?
Например, чтобы скрыть все изображения на странице средствами JavaScript, нужно сначала вызвать метод
g e tE le m e n ts B y T a g N a m e
() и передать ему аргумент
" i m g " , выделив таким образом все узлы изображений. Затем Q ; Выбор метода зависит от того, нужно ли вам выделить один элемент или же группу сходных элементов, в первом случае
останется изменить свойство v i s i b i l i t y языка CSS каждого из элементов. Но мы немножко забежали вперед, к DOM
следует использовать метод g e t E l e m e n t B y l d достаточно указать идентификатор элемента.
знать, что, хотя метод
() —
Если же вашей целью является группа узлов, лучше воспользоваться методом
378
глава 8
g e tE lem en tB y T ag N am e ().
и CSS мы вернемся позднее. На данный момент вам достаточно
g e tE le m e n ts B y T a g N a m e () (),
применяется реже метода g e t E l e m e n t B y l d в некоторых ситуациях без него не обойтись.
управление страницами
То есть свойства узлов позволя ют проникать в код НТМЬ и получать доступ к содержимому страниц... А как насчет изменения этого содержи мого? _______ /
Свойства D O M позволяют редактировать содержимое веб-страниц и поддерживать соответствие стандартам. Так как в D O M веб-страница представлена в виде набора узлов, именно их редактирование приводит к изменению ее содержимого. Текст в таких элементах, как div, span или р, всегда фигурирует в виде дочернего узла или узлов. Если текст содержится в едином узле, без дополнительных элементов H TML, значит, м ы имеем всего один дочерний узел. Рассмотрим пример:
d o cu m e n t.g e tE le m e n tB y ld (" s t o r y " ) . f i r s t C h i I d . nodeValue
Ты не один. Ш ТУРМ Каким образом DOM позволяет менять текст?
далее >
379
детские проблемы
Редактирование те к ста Если для простоты предположить, что существует только один дочерний узел, который и содержит текст, то ничто не помешает нам назначить этому узлу новый текст при помощи свойства nodeValue. Н о еще раз напомним, что дан ный подход работает только при наличии единственного дочернего узла. d o c u m e n t . g e t E l e m e n t B y ld C 's t o r y " ) . f i r s t C h il d . n o d e V a l u e = "OK, может быть ты один."; LEMENT Текст в дочернем узле заменен новой версией.
TEXT "ОК, может быть, ты один.
Н о проблема не всегда решается так просто. Что делать, если дочерних узлов несколько, как в слу чае вот такого кода? <р id = "sto rY "> LEMENT Ты < stro n g > н e < /s tro n g > один. </р> Эта с т р о ка содержится в целом наборе дочерних узлов.
TEXT
ELEMENT
Г "Ты"
j
strong
I
Л
TEXT
"один.'
К Р едакт ирования содержимого пер во го дочернего узла нед о ст а т о ч н о для изм ен ен и я всей
ст роки.
TEXT
Л Причиной появления набора узлов являю т ся дополнит ельны е теги.
Пр и замене содержимого первого дочернего узла остальные узлы не изменятся, и м ы получим странный результат:
d o c u m e n t . g e t E l e m e n t B y I d ( " s t o r y " ) .f i r s t C h i ld . n o d e V a l u e = "OK, может быть ты о д ин .";
Редакт ирует ся т олько со держимое первого дочернего узла , все ост альное о с т а е т ся без изменений... 380
глава 8
может быть, ты один)^ ^ д и н . у
у
управление страницами
Три шага для изменения Итак, м ы убедились, что замена значения одного узла не влияет на состояние остальных. Получается, что для редактирования информации в данном случае нужно сначала удалить все дочерние узлы, а затем добавить новые, уже с но выми значениями. ^
Удаляем все дочерние узлы.
О
Создаем текстовый узел с новым значением. Добавляем его в качестве дочернего узла.
Для этого нам потребуются три метода:
Удаляет дочерний узел, пере данный ему в качестве аргу мента.
©
Г
createTextNode() Из строки создает текстовый узел.
О appendChild() Добавляет переданный ему узел в ка честве последнего дочернего узла. Для редактирования текста «ты не один» нам потре буются именно эти методы. Сначала убедимся, что все дочерние узлы удалены, затем создадим новый тексто вый узел и, наконец, добавим его к строке. '
Выделим элемент (узел) но его IP-
v a r node = docum ent. g e tE le m e n tB y ld (" s t o r y " ); w h ile (node. f i r s t C h i l d )
Удаляем дочерний узе л, пока --------- — не очист им весь Массив.
n o d e . rem o ve C h ild (n o d e. f i r s t C h i l d ) ; n o d e . app en dC hild(d ocum ent. c r e a te T e x tN o d e ("OK, может быть ты о д и н . " ) ) ;
0
4
J
После удаления всех — ^ дочерних узло в до бавим родит елю новый т екст овы й узел.
O
K
^ Создадим новый
т&кстобый узел,
(б к , может быть, ты далее у
381
DOM о себе
Интервью недели: Загадочные, но мощные регулярные выражения Head First: Мне говорили, что вы являетесь са м ы м маленьким кирпичиком в D O M , своего рода атомом в H T M L -содержимом. Это так? Узел: Н е знаю, насколько я атомарен, но не могу не согласиться, что в дереве D O M я представляю именно дискретные фрагменты информации. Представим, что D O M разбивает каждую веб страницу на байтовые кусочки... Вот таким кусоч ком я и являюсь!
Head First: А почему это имеет такое значение? Зачем нужна возможность деления страницы на фрагменты? Узел: Это важно только в случаях, когда вам тре буется доступ к информации или возможность ее редактирования.
Head First: А не рискуем ли м ы в процессе такого деления потерять какой-нибудь фрагмент? Ведь часто люди разбирают что-то на части, а потом оказывается, что вещь банально сломана.
Узел: При работе с D O M такой проблемы не возникает, ведь вам не приходится в буквальном смысле разбирать страницу. D O M всего лишь представляет ее в виде иерархического дерева.
Head First: Даже так? А вы, я так понимаю, выхо дите на сцену, когда требуется что-то упростить?
Узел: Да. Н о речь не идет только об упрощении, к дереву можно ведь и добавить данные.
Head First: Потрясающе! А как все это работает? Узел: Помните, что каждый фрагмент информа ции является узлом? Вот через узлы и осущест вляется доступ к содержимому страниц. М о ж н о создать новый узел и добавить его к дереву. D O M — крайне гибкая структура.
382
глава 8
Head First: А как вы связаны с элементами? Или это просто еще одно ваше имя? Узел: П о большому счету, да. Элемент — это всего лишь еще один способ восприятия тегов, напри мер < d i v > или <sp an > . Все элементы страницы представлены на иерархическом дереве в виде узлов, так что можно сказать, что м ы одно целое. Н о я могу представлять не только элемент, но и хранящееся в нем содержимое. Так, тексту, хранящемуся в контейнере < d iv > , соответствует собственный узел, дочерний по отношению к узлу d iv . Head First: А как не перепутать элемент с его со держимым?
Узел: Начнем с того, что в дереве D O M содержи мое всегда представлено в виде дочерних узлов. Кроме того, каждый узел имеет собственный тип: для элементов это тип ELEMENT, в то время как их содержимое относится к типу TEXT.
Head First: То есть для доступа к хранящемуся в элементе тексту мне потребуется узел типа TEXT? Узел: Да. Н о следует помнить, что свойство no d e T y p e возвращает лишь номера типов. На пример, типу TEXT соответствует номер 3, а типу ELEMENT — номер 1. Впрочем, это можно не запо минать, ведь для доступа к содержимому элемента вам достаточно найти дочерний по отношению к нему узел.
Head First: Понятно. Спасибо, что согласились к нам прийти и рассказать про чудеса дерева DOM. Узел: Пожалуйста. И если когда-нибудь вы ре шите заняться приведением в порядок деревьев в вашем саду, не забудьте позвать меня.
управление страницами
Часто Задаваемые БоЩроСЬ! у э л е м е н т а р pElem .childN odes[z] т ри дочерних 1
Я не совсем понимаю, как систематизированы дочерние узлы. Например, как работает свойство
ч -^ -J L г ^ л -Г
childNodes?
_
^
Strong
1 Узел, содержащий данные, считается родительским. Данные,
0 ='
“ Г ” Элемент strong и м е
представляющие собой больше, чем лросто текстовую строку, формируют набор дочерних узлов. Этот набор указывается в свойстве
p E iem .ckM N o d e.s[0]
childNodes
родительского узла как массив. Порядок элементов массива определяется порядком появления узлов на странице. В результате для получения доступа к первому дочернему узлу достаточно написать
childNodes [ О ] .
Для поочередного
ет один до< черний узел.
,"
доступа ко всем дочерним элементам используются циклы.
Ql
Вот как выглядит это условие:
while(node.firstChild) Мы проверяем, присутствует ли в родительском узле первый дочерний узел, в случае положительного ответа возвращается значение true, и цикл продолжает работу. Отрицательный ответ означает, что дочерних узлов больше не осталось. Выражение
node.firstChild приобретает значение null, которое автоматически преобразовывается в false. После этого происходит выход из цикла.
Б:
Каким образом выполняется проверка условия в цикле while, код которого удаляет все дочерние узлы?
Магниты JavaScript в ООМ-совместимой версии «Приключений» отсутствуют несколько важных фрагмен тов. Расставьте магниты таким образом, чтобы получить код, меняющий содержимое текстового узла. Каждый магнит может быть использован несколько раз.
/ / Обновление описания сцены = d o c u m en t.g etE lem en tB y ld (" Vo.]-
)
w h ile ( (
(document. c re a te T e x tN o d e (
));
далее ►
383
решение задачи с магнитами
Решение задачи с магаитами Вот как выглядит код, меняющий содержимое текстового элемента.
Ц икл работ ает , пока ост ает ся кот я бы один дочерний т екст овы й узел.
Ц икл работ ает , пока суш ,ест вует первый дочерний узел.
Выделилл т екст овы й элем ен т по его IP.
Переменная message содержать >^олшо т екст , без ф орм ат ирования и тегов.
Обновление описания сцены sceneTexI Л = d o c u m e n t . g e t E l e m e ^ ^ I d C w h ile (
firstChild
sceneText
sceneText
I
i
I
F
removeChild к (
sceneText
^ ^ ^ ^ p ^ ^ K h i W j ^ d o c u m e n t . createT extN o de {
По очереди удаляем первые дочерние элем ент ы до п о л ного их исчезновения.
д Теперь, когда дочерних элем ент ов не о с т а АОСЬ) добавление И00020 т екст ового узла га р а н т и р у е т полную зам ену т екст а.
После удаления всех предш ест вую щ их дочер них элем ент ов созда ет ся новый т екст овы й узел, кот орый добавля ет ся в качест ве дочер него.
КЛЮ ЧЕВЫЕ МОМЕНТЫ
384
Свойство innerHTML, не входящее в стандарт, дает доступ ко всему содержимому элементов.
В DOM веб-страницы представлены в виде дерева связанных узлов.
Объектная модель документа, или DOM, предо ставляет стандартизованный механизм доступа к данным и их редактирования.
В DOM редактирование содержимого страницы включает в себя удаление всех дочерних узлов эле
глава 8
мента, с последующим созданием и добавлением дочернего узла с новым содержимым.
управление страницами
«Приключение», совместимое со стандартами Разве это не здорово! Признаком хорошего «Приключения» стало соответствие стандартам. В ы согласны? В контексте современных веб-приложений это большое преимуш;ество. Важнее всего значительные изменения, которые благодаря D O M произошли с описаниями сцен...
Да, внешний вид страницы не поменялся, но теперь, благодаря D O M , она сконструирована в соответствии с новейшими веб-стандартами. Далеко не всегда код JavaScript можно оценить визуально. Так и в данном случае, изменения коснулись аспектов, находяш,ихся «за кулисами».
Стандарт DOM предоставляет больший контроль над редактированием HTML, чем свойство innerHTML. далее >
385
улушвнныв варианты
В поисках лучших Вариантов к настоящему моменту текстовые описания сцен были дважды переделаны, а вот вид кнопок так и не поменялся. А ведь можно придумать более понятный способ перехода к следующей сцене, нежели выбор межд)' цифрами 1 и 2! Кнопки с цифрами прекрас но выполняют свою работу, но все-таки стоит их сделать более наглядными.
Pleasechoose; I
Цифровые кнопки неудачны, т ак как они не даю т предст авления о т о м , куда после их нажатия от правит ся пользоват ель. Нужно снабдить кнопки кратким описанием ситуации, в которую в результате нажатия одной из них попадет поль зователь. То есть, если предстоит совершить выбор между «Перейти через мост» и «Остановиться на мосту и посмо треть на воду», кнопки могут выглядеть вот так: Ш Л
B rU ge
G a ise h te Stream
Намного лучше! Г е п ^ _ кнопки пом огаю т в п р и н я т ии решения. Для решения нашей задачи не нужны кнопки ф ор м ы — с этим справится любой элемент HTML, служащий контей нером для текста. А в оформлении кнопок помогут сти ли CSS.
Ш ТУРМ Каким образом реализовать отображение на кнопках текста с кратким описанием следующей сцены?
386
глава 8
управление страницами
Проектирование лучше, варианты чии^е Так как новые кнопки перехода в «Приключениях» представляют собой H T M L -элементы, содержащие текст, для динамического изменения их содержимого воспользуемся средствами DOM. В результате для каждой сцены будет задаваться не только свое описание, но и свой вид кнопок. Значит, функции changeScene () потребуются две новые переменные для хранения еще двух тек стовых фрагментов. Назовем их decisionl и decision2. Вот каким образом в функции changeScene () будет задан текст для кнопки перехода от сцены 1 к сцене 3: curScene = 3; message = "You a r e s t a n d i n g on t h e b r i d g e o v e r lo o k in g a p e a c e f u l stre a m , d e c i s i o n l = "Walk a c r o s s b r i d g e " ; Т екст с описанием возможных вариант ов перехода хранится^ в переменны х decision! и decisionZ-
d e c is i o n 2 = "Gaze i n t o s tre a m " ;
Возьми в руку карандаш Динамически меняющиеся надписи на кнопках в нашем «Приклю чении» требуют нового подхода. Напишите код для новых тексто вых элементов, которые заместят кнопки <input>. Подсказка; класс CSS-стиля для новых элементов называется «decision». В самой первой сцене на кнопке должен присутствовать текст «Start Game»
(Начать игру). Pksiscchoose;
'>
Га:"'ГсГв1Гп2'.'.
Н апиш ит е код для кнопок, т екст на кот оры х меняет ся Iдинамически!
SttrttSere
далее k
387
реш ение упражнения
- ^ з ь м и в руку карандаш 'ешение Итак, вот новый код для текстовых элементов, которыми мы заме ним ранее использовавшиеся кнопки < in p u t > :
Please choose:
I
j
2
<lnput type="button" id="declsionl" v a l u e - n - onclick="changeSce.ie (1) " /> <inp“t tffe="button" id-"decision2" value="2" onclick="c:hangeScene(2) />
Дбе кнопки
превращаются в элементы span. Stan Game
I
А
I не создать ли нам функ цию для замены текста в узлах?
U сноВа замена те к ста В узлах Для того чтобы кнопки в «Приключениях» стали функциониро вать нужным образом, не хватает кода, задающего текст в эле ментах span. П о большому счету он должен работать аналогично написанному ранее для динамической замены описания сцены коду D OM . Основная проблема в том, что теперь нам каким-то образом нужно решить одну и ту же задачу для трех элементов сразу: для описания сцены и двух кнопок перехода...
388
глава 8
управление страницами
Функция, заменяюи^ая т е к с т узла Функция, реализующая замену текста в узлах, пригодится нам не только для «Приключения». Она должна работать по прин ципу ранее написанного нами кода замены описания сцены. У этой функции будет два аргумента:
f u n c t i o n re p la c e N o d e T e x t(id , newText)
{
, узла, т е кс т к о т орого нам нужно поменят ь.
Новый т екст . В качестве аргументов функции replaceNodeText () выступает, вопервых, идентификатор узла, содержимое которого следует заменить, во-вторых, новый текст, функция позволит редактировать любые эле менты, являющиеся текстовыми контейнерами. В «Приключениях» она будет динамически менять текст описания сцены и переходных кнопок. Н о сначала нам нужно будет написать ее код. Теперь мы в м е ^ ст о т рехкрат ного Л написания одного и т ого же кода т ри раза вызываем функции).
кг~ r e p la c e N o d e T e x t ( " s c e n e t e x t " , m e ss a g e );
Замена т екст а 'с описанием сцены.
r e p la c e H o d e T e x t ( " d e c is i o n l " , d e c i s i o n l ) re p la c e N o d e T e x t( " d e c is io n 2 " , d e c is io n 2 )
Замена т е к ст а двух кнопок перехода.
реш ение упражнения
Возьми в руку карандаш
^ВОЗЬМ!
Решение
Вот код функции r e p la c e N o d e T e x t {), меняющей текст в узле с указанным ID.
Выделяем элем ент по его ID. function replaceNodeText(id, new Text) { var node = docum ent.getElem ent8yld(id)-,
Удаляем все дочерние узлы.
while (node.firstChild) node.removeChild(node. firstChild);
Создаем новый дочер ний элем ент , используя переданный в качестве аргум ент а т екст .
node.appendC hild(docum ent.createTextN ode(new Text)); } функция createTextNodeQ дост упна т олько в объект е d o cu m en t и не связана с о т дельными узлам и.
Динамические параметры Новые варианты кнопок перехода с динамически меняющимся текстом более наглядны, чем кнопки с номерами из предыдущей Динамиче( ский, нагляд/ ный, восхититель-
390
глава 8
управление страницами Часдао
'^адаБаеМые БоИроСь! Где оказывается узел, созданный функцией c r e a t e T e x t N o d e ( ) ?
Почему вместо элементов d i v в «Приключении» используются элементы s p a n ?
содержать только текст?
; Так как кнопки выбора должны располагаться рядом, для их задания не могут использоваться блочные элемен ты, такие как d i v . Соответственно, мы применяем для них строковой элемент span.
Созданный при помощи функции c r e a t e T e x t N o d e ( ) узел может
Q ; Нигде. В первый момент созданный текстовый узел оказывается в неизвест ности, по крайней мере с точки зрения дерева DOM. Вы вручную должны добавить его к уже существующему узлу в качестве дочернего, и после этого он оказывается в структуре дерева.
! Да. При работе со свойством in n e r H T M L вы можете назначать текст прямо с тегами. А вот в DOM сло восочетание «текстовый узел» означает только текст, без всякого форматиро вания.
интерактивность Новые варианты кнопок перехода намного лучше нредыдуш;их, но даже их можно усовершенствовать. К примеру, можно сделать так, чтобы кнопка подсвечивалась при наведении на нее указателя мыши, как бы подсказывая, что на ней можно ш,елкнуть.
W alk a r o m d Back
Текстовые элем ент ы вы деляю т ся при наведении на них указат еля мыши.
Knock on D oor
J
Я была уверена, что все эти визуальные эффекты связаны с CSS, а не с DOM.
П о д с в е ч и в а н и е э л е м е н т о в с в я з а н о с C SS, н о и м е е т н еп оср едств ен н ое отнош ение и к D O M .
Подсвечивание содержимого веб-страницы реализуется средствами CSS, так как оно связано с небольшим изменением фонового цвета элемента. При этом D O M обеспечивает про граммный доступ к CSS-стилям элементов... далее у
391
элегантные стили
Значение стиля: C SS и DOM CSS-стили связаны с H T M L -элементами, в то время как D O M обе спечивает доступ к стилям посредством элементов (узлов). П р и менение D O M к редактированию CSS-стилей позволяет динами чески менять вид страницы. Стили назначаются элементу через класс styl^. <span i d = " d e c i s i o n l " c l a s s = " d e c i s i o n " o n c lic k = " c h a n g e S c e n e ( 1 ) " > S t a r t Game</span> <span i d = " d e c i s i o n 2 " c l a s s = " d e c i s i o n " o n c lic k = " c h a n g e S c e n e ( 2 ) "></span>
< s ty le ty p e = " te x t/c s s ”> sp an .d ecisio n
{
fo n t-w eig h t:b o ld ;
Внешний вид кнопок перехода определяет их класс style.
b o r d e r : t h i n s o l i d # 000000; p a d d i n g : 5px; b a c k g r o u n d - c o l o r : #DDDDDD;
I
) < /sty le >
D O M предоставляет доступ к классу стилей элемента при по мощи свойства className узла. a l e r t ( d o c u m e n t . g e t E l e m e n t B y l d ( " d e c i s i o n l " ) .c l a s s N a m e ) ; Свойство className дает дост уп к классу ст илей элем ент а.
decision
Свойство className узла предоставляет доступ к классу стилей. 392
глава 8
Не путайте классы сти РуДыпе I лей CSS оСШо р^ о ЖН ы ! с классами JavaScript. t o
Классы стилей в CSS и классы в JavaScript не имеют между собой ничего общего. В CSS классом на зывается набор стилей, ко торый может быть приме нен к элементу страницы, в то время как в JavaScript классом называется шаблон создания объектов. Более подробно классы и объекты будут рассматриваться в главе 10.
управление страницами
Замена классоВ стилей
К ласс ст илей dec\яoniv\verse ■меняет щВетовую схему к н о п ки перехода.
Чтобы поменять внешний вид элемента, достаточно указать для него имя другого класса стилей.
d o c u m e n t.g e tE le m e n tB y ld C 'd e c is io n l" ).c la s s N a m e = " d e c i s i o n i n v e r s e " ; Вид т ой же самой кнопки перехода после замены класса ст илей!
<style type="text/css"> span.decisioninverse { font-weight. -bold,•
Новый класс стилем был на значен кнопке перехода при поМош,и свойства className.
font-color;#FFFFFF; border:thin solid #DDDDDD; padding:5px;
Start Game
background-color:#000000;
) Замена класса стилей элемента в свойстве className немедленно отражается на внешнем виде элемента. Данная техника позволяет кардинальным образом менять внешний вид элементов страницы, не тратя практически никаких усилий.
</style>
Возьми В руку карандаш Напишите код для элемента < s p a n > кнопки перехода, который при помощи событий o n m o u s e o v e r и о п т о и з е о и 1 меняет класс стиля при наведении на кнопку указателя мыши. Подсказка: класс стиля, который используется при наведенном на кнопку указателе, называется d e c i s i o n h o v e r .
<зрап i d = " d e c i s i o n l " c l a s s = " d e c i s i o n " опс11ск="сЬапдеЗсепе(1)"
> S t a r t Game</span> <span i d = " d e c i s i o n 2 " c l a s s = " d e c i s i o n " o n click = "ch an geS cen e (2)"
></span>
далее ►
393
реш ение упражнения
Возьми Вруку карандаш Решение
Вот как выглядит код для элемента < зр а п > кнопки перехода, кото рый при помощи событий o n m o u s e o v e r и o n m o u s e o u t меняет класс стиля при наведении на кнопку указателя мыши.
К ласс ст иля declsionkover п о яв л яется б о т в ет на событие onmouseover.
<span i d = " d e c i s i o n l " c l a s s = " d e c i s i o n " o n c lic k = " c h a n g e S c e n e (1)" ^^^~^onm ouseover= "tkis.classN am e - 'decisionhover'" ............... > S t a r t Game</span>
e m n u Z f^ n p u
наведении у к а злтеля мыши на элем ент span.
<span i d = " d e c i s i o n 2 " c l a s s = " d e c i s i o n " o n click = "ch an qeS cen e (2)" >c9,'^,^omeoYer=4his.className - 'decisionkover'" o nm ouseout-4kis.classN am e - 'decision'"
></span>
Это событие возникает , когда ук а за т ель мыши убирает ся с элем ент а span. п.
Д аД аБ аеМ ы е
ка событие o n m ouseout
БоЦ|ЭоСЬ 1 Можно ли создать кнопку, которая подсвечивается при наведении на нее указателя, только средствами CSS?
0
Стильные Варианты Благодаря классам стилей кнопки перехо да в наших «Приключениях» теперь могут быть представлены в двух вариантах: обыч ном и подсвеченном.
! Да. В большинстве случаев именно так и следует посту пать, потому что CSS поддерживается ббльшим количеством браузеров, чем JavaScript. Но наши «Приключения» — это приложение, написанное на JavaScript, и многие его функции нельзя реализовать средствами CSS. Соответственно, мы соч ли возможным продемонстрировать другой подход к решению данной задачи.
<style type="text/css"> span.decision {
<style type="text/css">
font-weight:bold; border;thin solid #000000; padding:5px; background-color:#DDDDDD;
41
}
Единственным различием между эт им и классами ст илей являет ся цвет фона.
span.decisionhover { font-weight;bold; border:thin solid #000000; padding;5px; background-color:#EEEEEE;
</style> </style>
Обычный WaBt around Back Knock on Door
394
глава 8
управление страницами
Проверка работы приАО)кения Благодаря возможностям D O M менять класс стиля элемента по требованию наши «Приключения нарисованного человечка» получили новый интерфейс. Элли очень довольна.
Как Эффектно теперь выглядят кнопки перехода!
] л 1
Stick
»в®.
©Стучим
в M&pü
Y « have m ived м а
hfosefn й* « /« d s.
I '
■
Чаои-
Кнопки перехода т е перь подсвечивают ся при наведении на них указат еля мыши.
"^аДаБаеМые BoiiJ^oCbi
Б:
Они входят в стандарт?
' Почему для задания класса стиля |Гнопок перехода нам не потребовался кно метод g e t E l e m e n t B y l d {) ? мет
Q ; Да, на самом деле есть еще много стандартных событий JavaScript, с которыми вы пока не знакомы. Впрочем,
объектом, а в HTML-коде элемента доступ к объекту осуществляется при
^ 1яне помню событий
o n m o u s e o v e r и o n m o u s e o u t.
важно только то, как вы реагируете на событие, даже ничего не зная о нем. В данном случае по именам событий можно понять, что первое возникает, когда указатель мыши оказывается над
0;; Каждый элемент JavaScript является
помощи ключевого слова t h i s . В коде «Приключений» это ключевое слово относится к узлу элемента span. Именно этот объект при помощи свойства
Классы стилей — это здорово, но бы предпочел менять всего одно я 6i свойство. Это возможно? сво
0:; у вас замечательная интуиция!
Именно над этой проблемой бьется сейчас автор «Приключений» Элли. И эта проблема включает в себя применение JavaScript и DOIV! для индивидуального управления свойствами стилей...
classN am e
элементом, а второе — когда указатель
получает доступ к своему классу стилей. Поэтому для изменения
убирается с элемента.
класса стилей достаточно написать
t h i s . c la s s N a m e .
далее у
395
когда у кнопок нет имен
Пустая кнопка Данная проблема возникла давно, но до этого момента Элли старалась не обращать на нее внимания. Хотя из некоторых сцен возможен только один переход, отображаются все равно обе кноп ки, как показано на снимке экрана. С этим нужно что-то делать, потому что интерактивные элементы, не содержащие информа ции, создают путаницу.
stick Figure feJvervture
в О 0
Меня беспокоит наличие пу стых кнопок перехода в некоторых сценах. Они бессмысленны и толь ко путают пользователей.
VJelcONVe { о
STICK FIGURE ADVENTURE
в каких еще сценах присутствует данная проблема? Как ее можно решить?
396
глава 8
управление страницами
Настройка «а ля style» Иногда не нужно менять весь класс стилей. Для случаев, когда требуется большая детализация, существует объект style. Объ ект style доступен как свойство узла и дает доступ к индивиду альным стилям как к свойствам. Так, свойство visibility при меняется для управления видимостью элементов. В НТМЬ-коде «Приключений» вторую кнопку можно изначально скрыть:
Свойство style узла предо ставляет доступ к индивиду альным свойствам стиля.
<span i d = " d e c i s i o n 2 " c l a s s = " d e c i s i o n " o n c lic k = " c h a n g e S c e n e (2)" onmouseover=”t h i s . className = 'd e c i s i o n h o v e r '" o n m o u s e o u t= " th is . className = ' d e c i s i o n ' " s t y l e = ”v i s i b i l i t y : hidden'*>< / span> Таким образом, для изменения видимости элемента достаточно менять значение свойства visibility с visible на hidden и обратно.
:
у
d o c u m e n t . g e t E l e m e n t B y I d ( " d e c i s i o n 2 " ) .s t y l e .visibility = "visible"; d o c u m e n t . g e t E l e m e n t B y I d { " d e c i s i o n 2 " ) .s t y l e .visibility = "hidden";
^
Start Game
Возьми в руку карандаш ix Вт орая кнопка.
В некоторых сценах «Приключений» должна меняться видимость второй кнопки перехода. Пометьте эти сцены и укажите, каким образом должно осуществляться это изменение.
далее ►
397
решение упражнения
Возьми в руку карандаш, Решение
Вот каким образом в некоторых сценах «Приключений» долж на меняться видимость второй кнопки перехода.
Вт орая кнопка.
Start Game
Вт орая кнопка перехода __^ должна быть бо бсех — . сценах., из кот оры х возможен т олько один выход. ^
^
В т орой элем ент перехода нужно показат ь один раз в м о м ен т начала новой игры. Скрыть втоюой элем ент ^ р е б у е т с я б сценах, ведущ их к концу игры. В каждой сцене изменение оидимости вт орой кнопки Т/лл fУ y^^c m 6 ляem cя при помощ и свойства уШЬПЦц объект а 5Ы е.
case 7: if (decision == 1) { curScene = 6 , V message = "Sorry, you became the troll's tasty lunch. decisionl = "Start Over"; decision2 = // Скрыть вторую кнопку перехода d o c u m e n t . g e t E l e m e n t B y l d ( " d e c l s i o n 2 " ) .s t y l e . v i s i b i l i t y
else { curScene = 9; decisionl = decision2 =
} break;
398
глава 8
и
управление страницами
КЛЮ ЧЕВЫЕ МОМЕНТЫ Свойство className узла меняет весь класс
стиля этого узла.
Элементы страницы можно динамически прятать или снова делать видимыми при помощи свойства
visibility элемента.
Свойство style дает доступ к отдельным свой
ствам стиля узла. Классы стилей CSS не имеют ничего общего с клас сами JavaScript — это совсем разные вещи.
Аналогично дейст вует свойство ст иля display. Присвоив ем у зн а чение попе, вы скроет е элем ент , а присвоив значение block, наобо р о т , сделает е видимым.
Без фиктивных кнопок Управление отдельными стилями при помощи D O M позволяет по вашему выбору скрывать или делать видимой вторую кнопку перехода. В результате вы получаете более функциональный пользовательский интерфейс, ведь лишних кнопок больше нет. .»в».
PtgureAdventare
Т
_______________ (
WelcOhAG to
^
\
Намного лучше... эти пустые кнопки так раз дражали!
ST IC K FIGURE
Теперь в сценах, для к о т о рых вт орая кнопка п е р е хода не т ребует ся, она оказывается скрытой. далее >
399
старое, доброе дерево решений
Усло)княем «Приключения» Поскольку Элли собиралась написать длинную и интересную историю со множеством ветвлений, в управлении столь слож ной структурой ей поможет DOM.
Новые <<Приключения>> = Рост дерева решений!
Самая последняя версия «П риклю чений нарисованного человечка» уже выложена в И нт ернет е и ждет ваших дополнений. Если вы еще не скачали ее, сделайт е эт о по адресу k t t p : / / w w w .kea d firstla b s.co m /b o o ks/h ijs/.
400
глава 8
управление страницами
Столько развилок сюжета... Как же напи сать все эти проверки условий?
<
Вряд ли в ы напишете длинную историю без хорошего способа проверки условий. П о мере добавления новых сцен и переходов становится все слож нее обычным способом проверять условия и гарантировать, что на каждой развилке пользователь будет попадать туда, куда нужно. Поэтому нам определенно требуется новый механизм проверки условий.
ШТУРМ Каким образом лучше всего осуществлять проверку условий при таком огромном количестве ветвлений?
далее >
401
следуем по пути
Поход по дереву решений Браузеры умеют запоминать список посещенных пользователем страниц. Аналогичную функцию можно использовать в «Приключениях» для провер ки и отладки сюжетных ходов. Вам нужно выделить набор сцен, ведущий к определенному результату. Только таким способом Элли сможет убедиться, что все работает именно так, как ожидалось.
— РйЗЙилкй
История переходов конструируется как список посещенных по мере продвижения по игре сцен. Именно она потом будет ис пользоваться в качестве отладчика.
Начало Сцена О — Введение Выби рает ся первый вариант...
Сцена 1 — Развилка на дороге. Сцена 2 — Хижина в лесу.
♦
Сцена 3 — Ведьма в окне.
❖
Сцена 8 — . Сцена 11-
Конец
402
глава 8
■■■Которяя ведет к сцене 4.
Каждая пройденная сцена добавляется _к ист ории вм ест е с реш ением , к о т о рое к ней привело.
Ш ТУРМ Каким образом следу ет изменить страницу «Приключений» для включения поддержки «истории пройденных сцен»?
управление страницами
Превратим историю в HTML с точки зрения H T M L
код истории решений не является слиш ком сложным: вам понадобится элемент d i v и строка текста, описывающая следующую сцену.
Каждый элем ент р содержит один из п ун кт о в ист ории переходов.
<div i d = " h is t o r y " > <p>Decision 1 -> Сцена 1
Развилка на д о р о г е .</
<p>Decision 1 -> Сцена 2
Хижина в л е с у .< /р >
<p>Decision 1 -> Сцена 3
Ведьма в окне.</р>
</div> Осталось написать K O A ja v a S c r ip t, который при помощи D O M превратит историю посещений в набор узлов.
(
ФуНКЦИЯ фиКСЯЦИИ ИСТОрИИ
посещенных страниц может быть полезным инструментом отладки.
А разве мы можем создавать новые строки по желанию?
D O M позволяет создать любой H T M L -элемент. А значит, вы можете создать и строку. Для этого вам потребуется еще один метод объекта документа c r e a t e E l e m e n t (). Именно он создает новый контейнер, в который вы добавляете текст, формируя дочерний узел при помощи функции c r e a t e T e x t N o d e (). В результате на дереве появляется новая ветка узлов. div I
document.createElement("р");
Г
ELEMENT
docviment.createTextNode (" .. . ") ;
Vs____ TEXT "Decisxon 1 -> Сцена 1 : Развилка на д о р о г е . ” |
mp далее >
403
манипулируем с HTML
Обработка НТМ1-кода Для создания нового элемента методом c r e a te E le m e n t () достаточно указать имя тега. Так, чтобы создать элемент (р), достаточно вызвать метод с аргументом "р" и указать, куда при соединить конечный результат.
Мы начнем с нового элемента р , «парящ его ° ‘п р о ст р а н ст в е » .
v a r d ec isio n E lem = document. c r e a t e E l e m e n t (" р " );
Итак, у нас есть новый элемент без содержимого, пока еще не принадлежащий никакой странице. То есть нам нужно доба вить к нему текст, создать текстовый узел и добавить его в каче стве дочернего к узлу р. d e c is io n E le m .a p p e n d C h ild C 'D e c is io n 1 -> Сцена 1 : Развилка на д о р о г е . " ) ) ; Э л е м е н т р до сих пор никуда не присоединен, но он перест ал быть п у с т ь , м благодаря новому дочер нему т екст овом у узлу ^
" D ecisio n 1 -> Сцена 1 : Развилка на д о р о ге.'
Теперь новый элемент нужно добавить в качестве дочернего к элементу d iv истории переходов. d o c u m e n t .g e t E l e m e n t B y I d ( " h i s to r y " ) . app en dC hild (d e cisio n E le m ) Элемент и добавлен о качестве дочернего к сущ ест вую щ ем у эле м ент у div, то ест ь он оказался в составе веб страницы.
<div id="history">
" D e c is io n 1 -> Сцена 1 дороге.
^^<p>Decision 1 -> Сцена 1 : Развилка на дороге.</
</div>
Повторяя эти процедуры при каждом переходе к новой сцене, мы динамически формируем историю «Приключений».
404
глава 8
Развилка на
управление страницами
-ft-
КЛЮ ЧЕВЫЕ МОМЕНТЫ
Все HTML-элементы можно создать методом c r e a t e E le m e n t о объекта
Аккуратно добавляя и удаляя узлы на дереве DOM, можно по желанию разбирать страницу на состав
d o c u m e n t.
ные части и собирать обратно.
Для добавления текстового содержимого нужно соз дать текстовый узел и присоединить его к элементу.
Возьми в руку карандаш Напишите функцию c h a n g e S c e n e ( ) , фиксирующую историю пройденных сцен в «Приключениях». Подсказка: когда текущая сцена отлична от нулевой, нужно добавить новый параграф с до черним текстовым узлом к элементу с историей переходов. Для сцены номер о нужно удалить историю.
f u n c t i o n c h a n g e S c e n e (d e c is io n )
{
/ / Обновление истории пройденных сцен
далее *
405
реш ение упражнения
щМьт в руку карандаш Решение
Вот код функции c h a n g e S c e n e ( ) , фиксирующей историю пройденных сцен в «Приключениях».
АобавиМ новый т е к стовый узел к новом у п а р а гр а ф у.
ф ункция changeSceneQ уже снабжена локальной п е р е м е н ной decision, п о э т о м у данной
f u n c t i o n c h a n g e S c e n e (d e c isio n )
{
переменной присваивает ся другое имя. В ы делим связанные
с ист орией элем ент ы по и д е н т и ф и к а т о р у .
/ / Обновление истории пройденных сцен_»^ var history = d o cu m en tg etE !em en tB yfd ("h isto ry”); if (curScene != о) {
var " + decision ........' 1 . 7 . ^ , [[.t.9!^^.ccne + "..•■..t.
history.appendChi!d(decisionElem);
^ Д о б а ви м новый
параграф к элем ент у div.
} eise ( // Удалим ист орию переходов while (history.firstChild)_
О чист им ист орию , уд а ли в все дочерние узлы .
406
глава 8
Создадим новый т екст овы й узел с инф ормацией о переходе к оче редной сцене.
управление страницами
ОтсАе)кивание «Приключений» Функция фиксации истории в «Приключениях нарисованного человеч ка» дает возможность аккуратно отследить логику происходящего. .аде — ------
VJelcoweto
STICK FIGURE adventure /->4 » © J Л
Vour journey begha at a f a t in ee io» 3. [f»fce tt e ftw H j [ T . t o l l« m % > | DedsiM b > S e e * t ; Y a » jOBrtcy Ьедп» * • f t r t m the Л1В 1
—
I
,Приключения еще не начались, поэт ом у ист ория пока о т сут ст вует .
Благодаря новой функции я могу заняться творчеством, не упуская контроля над де ревом переходов.
Ист ория р а ст ет по м ере продви жения по сценам.
V
«I» t o 1
„Sfc,„ И*„ ^
^
Фиксация ист ории заканчивается в п о следней сцене.
далее *■
407
бесконечная история
Длинное, странное путешествие... Что ж, пришло время напрячь вашу фантазию и превратить «Приключения нарисованного человечка» в настоящую длин ную игру, на примере которой можно будет осуществить отлад ку функции, фиксирующей историю. Ваш нарисованный друг ждет приключений...
аЖ Н бИ И б
Придумайте ваше собственное продолжение «Приключений нарисованного чело вечка» и добавьте соответствующий код. Для этого упражнения не существует готового решения... Так что получайте удо вольствие от самостоятельных приключений!
408
глава 8
управление страницами
Вкладка Согните страницу по вертикали, чтобы совместить два мозга и решить задачу.
Так что же это такое, DOM? ---------
\% ! хо|>оШо,
а ДВа лучше!
<:-----
D o cum ent I.
Программистам JavaScript не следует сильно увлекаться DOM. Эта функция дает доступ к HTML-тегам, но старайтесь не слишком ею злоупотреблять.
данные
Объекты как франкенданные
Объекты иауаЗспр! вовсе не так ужасны, как заставил вас думать доктор. Зато они интересны тем, что соединяют друг с другом отдельные части языка иауаЗспр!, делая его более мощным. Объекты объ единяют данные с действиями в новый тип, намного более «живой», чем все, что вы использовали раньше. Вы познакомитесь с массивами, которые сортируют себя сами, со строками, которые умеют искать в своем составе указанные последовательности символов, и многими другими замечательны ми особенностями.
время веселиться
Вечеринка В стиле JavaScript Давайте устроим вечеринку. Вам нужно пригласить на нее гостей. Какая информация вам для этого требуется?
Где? К то?
Когда?
(^^^Приглашенный^
Д анны е п р и глаш ен ия.
Отобразишь!
Д ейст вия для приглаш ения.
Доставить! оставить данные
^Отобразить данные
В JavaScript смоделировать приглашения на вечеринку можно, представив данные в виде переменных, а действия в виде функций. Пр и этом м ы сталки ваемся с проблемой, которой не существует в реальном мире, — как разде лить данные и действия. Ч т о?
Д ост авка! К то? You’re invited to. Оборотная сторона!
A Puzzle Party! October 24th ^
Date:
Puzzler Ruby
2112 Confounding Street Location: 95099 иЗА
5280 Unravel Avenue Conundrum, AZ 85399 USA
Когда?
Л Где?
Отображение!
Реальные приглашения совмещ;ают данные и действия в одной сущности, называемой объектом.
412
глава 9
оживляем данные
Данные + действия = объект в 5ауа8спр1 вовсе не обязательно всегда соблюдать раздельный режим работы с данными и действиями. Более того, существует такая уникальная структурная единица, как объект, одновременно хранящая данные и выполняющая над ними различные действия. Рассмотрев приглашения на вечеринку с точки зрения объектов JavaScript, получим следующую схему:
О бъ ект Данны е var who;
Д ействия function display(what, when, where)
{
function display!)
{
function deliver 0
{
var what; var when; var where;
Вне объект ов данные передаю т ся ф ункциям в виде аргум ент ов. В объекте invitation данные и функции существуют одновре менно и близко связаны друг с другом. Функциям, помещенным внутрь объекта, уже не нужно передавать данные в виде аргумен тов, так как эти функции имеют к данным прямой доступ.
Объекты связывают данные и функции в пределах одного контейнера. Данные внутри объекта доступны для функции, но скрыты от внешнего мира. Поэтому объект можно рассматривать как контейнер, хранящий данные и связывающий их с об рабатывающим кодом. далее >
413
привилегии для членов
Данные — это собственность объекта Помещенные в объект данные и действия принято называть членами объекта. Переменные также называются свойствами, а функции мето дами. Эти структурные единицы по-прежнему выполняют свои функции, то есть хранят данные и выполняют над ними различные операции, но теперь они делают это в контексте определенного объекта. *^® реме
Свойства и методы объекта являются эквивалентами переменных и функций.
414
глава 9
Свойства и методы являются «собственностью» объекта. Это означает, что они хранятся внутри объекта, примерно как дан ные внутри массива. Для доступа к свойствам и методам исполь зуется специальный оператор, называемый «точкой».
О бъект
С в о й с т в о /М е т о д
Г"
И мя объекта.
обычная точка.
Имя свойства / или метода.
оживляем данные
Ссылка на члены объекта Оператор «точка» устанавливает связь между свойством или ме тодом и объектом, к которому они принадлежат. Примерно так же, как имя дает представление о самом человеке, а фамилия, о том, из какой он семьи. Вооруженные этими знаниями, соединим данные для объекта invitation. Для этого нам понадобится перечень его свойств и оператор «точка»:
Оператор <<точка>> дает ссьику па свойства или методы объекта.
Имя свойства. Имя объекта.
i n v i t a t i o n . who = " P u z z le r Ruby"; i n v i t a t i o n . w h a t = "A p u z z le p a r t y ! " ; i n v i t a t i o n . w h e n = "O ctober 2 4 th " ; i n v i t a t i o n . w h e r e = "2112 Confounding S t r e e t " ; Точка da&m дост уп к каждому из свойств. Помните, что, так как данные и действия являются частью одного объекта, методам не нужно передавать какие бы то ни было параметры. В результате любые действия с объектом invitation выполняются очень просто: i n v i t a t i o n . d e l i v e r (); . Имя метода. И м я объекта.
ажнение
Нашим приглашениям не хватает свойства, позволяющего ответить, придет гость на вечеринку или нет. Напишите код, добавляющий объекту свойство r s v p , а затем вы зовите метод з е п с 1 к з у р { ) , ответственный за отправление ответов.
далее >
415
спроси у меня что угодно
ажнение
Вот как выглядит код свойства r s v p , ответственного за отправку ответов на приглашения.
|''ешше invitation.rsvp^ = "attending"^ invitationsendRSVPQ ; О перат ор "т оч ка" дает ссылку на свойство и м ет од объект а invitation.
Сюда можно пост авит ь также булевское свойство. В эт ом случае значение tru e будет означать п р и н я т ое приглашение,, а значение false — отклоненное. Часгг1° Задаваемые БоЦроСь!
Что же такое «объект»? Принадлежит ли он к какому-нибудь типу данных?
к сожалению, в настоящий момент JavaScript не позволяет полностью защитить свойства объекта от доступа
! Объект представляет собой именованный набор свойств и методов. Собственно говоря, объект — это и есть тип данных. Уже знакомые вам типы включают в себя числа, тексты и логические значения. Они называются примитивными. Объекты же считаются составными типами данных, так как состоят из набора фрагментов информации. Соответственно, вы можете добавить к уже известным вам трем типам
извне. Кроме того, иногда возникают ситуации,когда к ним требуется
данных еще и тип «object». Именно этому типу будут принадлежать созданные вами или встроенные объекты JavaScript.
Я уже несколько раз видел запись с оператором «точка». Неужели я все это время пользовался объектами?
свободно расположенный где-то в сценарии (глобальная переменная).
Q ; Да, Скоро вы поймете, что сложно писать сценарии на JavaScript, не прибегая к объектам. Ведь этот язык — сам по себе лишь один большой набор
S Можно. Но проблема в том, что доступ к глобальным переменным возможен из любой части кода. А как
объектов. Например, функция alert по сути является методом объекта
мы уже упоминали, лучше оставлять доступ только тем фрагментам сценария, которым он действительно нужен. Это
написать
416
глава 9
alert().
непосредственный доступ. Впрочем, основная идея состоит в том, что помещенные в объект данные логически связываются с ним. А связанный с объектом фрагмент информации является более контекстным, чем
Нельзя ли вместо свойств и методов объекта просто использовать глобальные переменные и функции?
позволяет предотвратить случайное редактирование данных.
вы можете работать только с функцией
3 ' Я совсем запутался. Вы пытаетесь сказать мне, что функции это на самом деле методы? ; Да, хотя думать о функциях подобным образом вам пока непривычно. Как вы знаете, функция — это фрагмент кода, который можно вызвать по имени. 1\Летод представляет собой функцию, помещенную внутрь объекта. Другое депо, что с объектами связаны все функции. Например,
alert
{) — это
одновременно функция и метод, что объясняет возможность вызвать ее двумя способами. В данном случае, как и в ряде других, в качестве объекта выступает окно браузера. Так как этот
()
window, то есть для ее вызова можно window . alert () . Объект window представляет собой окно браузера и в явном виде ссылаться на него необязательно. Собственно, поэтому
объект по умолчанию используется при вызове методов, если в явном виде не указано иное, можно считать, что метод
alert
() является функцией.
оживляем данные КЛЮ ЧЕВЫЕ МОМЕНТЫ
ь
Объектами называют особые структуры, объеди няющие данные и обрабатывающий их код.
Помещенные в объект переменные превращаются в свойства, а функции — в методы.
С практической точки зрения объект — это все
Для ссылки на свойство или метод достаточно ука
го лишь переменные и функции, объединенные в структурную единицу.
зать имя объекта, затем - точку, а затем свойства или метода.
имя
Блог для любителей головоломок Инициатором вечеринки, для которой м ы создаем приглашения, является І^би — фанатка головоломки «Кубик Рубика». Она мечтает о встрече с людьми, разделяюш;ими ее страсть. При этом Руби хотела бы не только устроить вечеринку для единомышленников. Она решила завести блог YouCube, посвяш;енный головоломкам.
Я слышала, что объекты позволят упростить редактирование моего кода. Значит, у меня останется боль ше времени на головоломки!
Руби слышала, что вJavaScript поддерживаются специаль ные объекты, так как это позволяет создавать более устой чивый и управляемый код. Еще она слышала, что многие блоги устаревают, потому что пользователи прекращают ими заниматься. Поэтому Руби решила с самого начала создать объектно-ориентированный сценарий блога YouCube, который обеспечит ее прекрасное будущее.
О бъ ектноор иен тир ов анн ы й YouCube
Больш е вр ем ени на головолом ки!
далее >
417
по-старинке
Анализ блога YouCube Руби ведет обычный рукописный дневник. Читая чужие блоги, она узнала, что записи состоят из даты и текста, но ей пока непонятно, как сохранить эти данные при помощи JavaScript. А ведь Руби так устала писать на бумаге!
YouCube, н а писанный вручную.
0 8 /1 4 /2 0 0 8
Q ot th e n e w си б е I o r d e re d . I t s a reaC jje a r C
0 8 /1 9 /2 0 0 8
S o C v e d th e n e w cuB e B u t o f co u rs e , n o w I ’m B o r e d a n d s fio p p in g f o r a n e w one. Aam a записи'
•
0 8 /1 6 /2 0 0 8
^ M a n a g e d t o g e t a h e a d a c h e toiCing o v e r th e n e w cuBe. Текст записи.
g o t t a najy.
0 8 /2 1 /2 0 0 8
f o u n d a 7x 7^7 cuBe f o r saCe onCme. y ik e s! T h a t one couCd Be a Beast.
Руби отчсшнно нужен непосредственный механизм сохранения набора данных в форме (дата + текст) с последующим доступом к нему. В ы уже слышали подобные слова, когда м ы говорили об объектах JavaScript, ведь именно объекты позволяют соединить различные фрагменты информации в целостную структуру.
Дата зап и си + Тело запи си = Объект Blog
418
глава 9
Специальный объект объединяет в общую структуру два фрагмен та блога.
оживляем данные
Специальные объекты в JavaScript достаточно стандартных объектов, с частью которых м ы познакомимся в этой главе. Но, хотя эти объекты несомненно полезны, бывают случаи, когда их функциональности недостаточно. Примером такого случая является наш блог YouCube. Ведь проблема сохранения данных в нем не может быть решена при помощи встроенных объек тов JavaScript. А значит, нам не обойтись без специальных объектов.
Строки — эт о тоже объекты!
И массивы тоже объекты.
Если бы не было _ объект ов, можно было бы сохранят ь з а т е и блога в виде двумерного массиба.
О бъект В!од служ ит сост авным т и п о м дан ных, объединяя два ф р а г м ент а информации.
Специальные объекты позволяют добавлять к JavaScript функции, удовлетворяющие вашим потребностям. В случае Руби специальный объект моделирует записи блога, представляя дату и тело записи в виде своих свойств. Методы предоставят возможность смоделиро вать поведение записей блога, сделав процесс их создания и редак тирования более понятным. Н о перед тем, как воспользоваться таким специальным объектом, нужно понять механизм его создания...
далее >
419
осторожно: идет ст роит ельст во
Конструктор Так как с объектами связаны данные, процесс их создания дол жен сопровождаться присвоением начальных значений. Для этого используется метод, называемый конструктором. Для каждого специального объекта существует свой собственный конструктор, имя которого совпадает с именем объекта. Имен но этот метод отвечает за присвоение начальных значений. Поэтому при создании специального объекта так важно напи сать корректный конструктор.
За создание объекта отвечает конструк тор.
свойст ву ц /методы-
С озданы
function displayO
function deliver О
{
I„»itatl.n(w ho, w b a t, w hen, w here); . Имя конст рукт ора совпадает с им енем объекта.
С войст ва и ни ц ш
Iлизированы.
Н о вш обьект гот ов к использование^
Invitation
..... who = "Somebody"; what = "Something"; when = "Sometime"; where = "Somewhere";
var who = "Somebody"; var what = "Something , var when = "Sometime , var where = "Somewhere
Объект с конструктором создается при помощи оператора new. Этот процесс напоминает вызов метода. Собственно говоря, процедура создания объекта осуществляется через вызов его конструктора. Н о нельзя сделать это непосредственно, обяза тельно следует пользоваться оператором new. ■Оператор n ew создает новый объект. v a r i n v i t a t i o n = new Invitation("Somebody", "Som ething", "Sometime", "Somewhere"); ^
420
глава 9
Новый объект со краняет ся в эт ой переменной.
конст рукт ора совпадает с им енем метода.
^
Свойства задаю т ся п у т е м — передачи аргцм ент ов ко нст рукт ору.
оживляєм данные
Структура конструктора Конструктор задает свойства объекта вместе с их начальными значения ми. Для этого используется ключевое слово this. Оно связывает свойство с объектом и одновременно задает его начальное значение. С английского слово переводится как «это» и полностью оправдывает свое значение — вы создаете свойство, принадлежащее «этому» объекту, а не просто локальную переменную внутри конструктора.
Клю чевое слово this function Invitation (who. what, when, where) { от личает свойство объект а о т обычной this.who = who; переменной.
Л
this.what = what; this.when = when; this.where = where;
}
Имена конст рукт оров, как и имена объек т ов. всегда пиш ут ся с большой буквы.
А р гу м ен т ы к о н ст р ук т ора назначаются новым свойствам.
Тело конст рукт ора за клю чает ся в ф игурные скобки, как и у любой д р у гой функции.
Свойства объекта создаются и инициализируются конструктором при помощи оператора «точка» и ключевого слова this. Это ключевое слово дает конструктору понять, что он создает свой ства определенного объекта. В нашем случае результатом работы конструктора стало создание четырех свойств, которым были назначены значения, переданные в качестве аргументов.
Свойства объекта в конструкторе созданугся при помонщ ключевого слова this.
заставим это работзть
Возьми в руку карандаш Решение
Вот как выглядит конструктор для объекта Blog, создающий и инициализирующий дату и текст каждой записи. И мя кон ст рукт ора совпадает .function B!og(bodij, date.) { с им енем о 5 ъ - ...................... ...... ч ,, . , , , , ^ Т е к с т записи и дата екта. ...Р.у.‘.^.'..Р.^У..7..У.9.4!^.... . ~~~~—- — передаю т ся в каче-
^ Клю чевое слово this от сы лает к свойст вам объекта.
................
tkis.dau = }
Д л я инициализации свойст в использую т ся переданные о конст рукт ор аргум ент ы .
Создание объектов blog Объект Blog постепенно принимает некую форму, хотя он еще не создан. В теории все прекрасно, но его существование пока только гипотеза, которую нам предстоит доказать. Конструктор форми рует модель объекта, но физически у нас ничего нет, пока м ы не воспользуемся оператором new, который создаст объект, вызвав его конструктор. Ра^мотрим эту процедуру на практике
О бъект ßlog.
Продолжим на прим ерах, которые можно скачат ь на n tt p : / / w w w .headfirstlabs.com / books/hfjs/.
0 8 /1 4 /2 0 0 8
g o t the n e w cu b e I o rd e re d . I t s a reatpe^dT^'
v a r b lo g E n try = new BlogC'G ot th e new cube I o r d e r e d . . . " ,
Д л я создания о б ьект а вызывается конст рукт ор ßlog().
422
глава 9
Рукописная запись 6 блог.
" 0 8 /1 4 /2 0 0 8 " );
оживляем данны е
Часто
Ч аД аБ аеМ ы е БоІїросГьі
Я не понимаю, объект создается оператором n e w или конструктором? ; И тем и другим! Оператор n e w инициирует процедуру создания объекта и отвечает за вызов конструктора. При этом простой вызов конструктора как обычной функции без оператора n e w не приведет к созданию объекта. Точно так же бессмыспенно использовать оператор n e w без конструктора.
Всем ли специальным объектам требуется конструктор?
Исключением является случай создания чисто организационного объекта,
Б
• Что такое t h i s ?
состоящего из набора методов, не влияющих на свойства. Такой объект технически можно получить и без
Q l Это ключевое слово, используемое для ссылки на объект. Точнее, это ссылка на объект изнутри самого объекта. Да,
конструктора. Другое депо, что подобные структуры нельзя считать хорошей практикой объектно-ориентированного
звучит несколько странно. Но представьте, что вы потеряли часы в переполненной комнате, а кто-то их нашел. Когда их вам покажут, вы закричите «Это мои часы!» Словом «мои» вы ссылаетесь на себя. Более того, это слово указывает, что именно вы являетесь собственником
программирования, ведь они представляют собой не более чем набор связанных друт с другом функций. Но даже при таких условиях иауаЗспр! сам использует организационные объекты для группировки математически связанных задач, как вы увидите в этой главе.
часов. Ключевое слово t h i s аналогичным образом подразумевает собственность объекта. В результате запись t h i s . d a t e означает, что
SДа. Ведь именно конструктор отвечает за задание свойств объекта,
свойство d a t e принадлежит тому объекту, в коде которого оно появилось.
соответственно, без него объект не получит никаких свойств. А значит, его существование будет бессмысленным.
Возьми в руку карандаш
08/14/2008
^
^ r*v
Создайте массив объ ектов B l o g в пе рем енной b l o g , котор ой в качестве н ачального значения были присвоены записи блога YouCube. Записи полностью переписы вать не н уж но, достаточно огр ан и чи ться первы м и словами.
tfie new cuBe. I ordered. I t s a reaCpearC. got
08/19/2008
SoCved the new cube but ot course, now I ’m bored and sfiofrping f o r a new one. 08/16/2008
ManagecC to get a fieacCache toiCing o v e r Ше new cube, gotta nap. 08/21/2008
fo u n d a f o r sale onCtne. yi^es! That one could be a 0east. 7 x 7 x 7
далее *
423
решение упражнения
Возьми в руку карандаш
^В о зь м і
rv
Решение
Вот процедура создания массива объектов Blog в переменной blog, которой в качестве начального значения были присвоены записи блога YouCube.
08/14/2008
^
got the new cube I ordered. It a reaCpearC.
va r blog =
^
^ ordered...", "OS/X4-/ZOOS"), 08/19/2008
SoCvedthe new сиве h u t o f course, now I Ш vored and shopping f o r a new one.
BlogC'Solved the new cube b u t of course...", " 0 8 /1 9 /Z 0 0 8 " ) , ^
new B io g f Managed to g e t a headache toiiing...", " 0 S /1 & /Z 0 0 8 " ), new BlogC'Found a 7x7x7 cube for sale...", " 0 8 / Z t /Z 0 0 8 " )
* 08/16/2008
M a n a a e d to get a headache toiCing o v e r the new cube, gotta nap.
............................ ]i.............. Каждая запись созда■ется как объект Blog, содержащий т екст и дату.
08/21/2008
f o u n d a 7X 7X 7^u6e f o r sale , onCine. yike s! That one could be a beast.
Д анны е, хранящиеся в каждом объект е Blog, аккурат но о т о бражаются на с т р а нице YouCube.
Версия YouCube 1.0 Скомбинировав массив объектов Blog с кодом JavaScript, отображающим данные, м ы получим первую версию страни ц ы YouCube. Руби знает, что работа еще далека от заверше ния, но первые результаты ее радуют. ^ ^
YeuCabe - The
fe*" Cube Pi
YouCube - The Blog for Cube Putilers
Мне нравится, как объ ект Blog скомбинировал дату и текст на странице УоиСиЬе. » b e I o r i e t e d .I t 's a таlpe^lй• &
S
new cube
bu. coursenow of
.
Г»
ь о ш і and Л оррш в tor a
M w
get a headaehe toBtag over «1» new cube. G o » nap. f t * ^ x 7x 7 cube tor sale o n ta e . Ylkesl That one couM be a beast. _ 5h w A ! l« o g E n tfi« 1
Посмотрим, какой же код вдохнул жизнь в объекты Blog и сделал страницу YouCube 1.0 реальностью...
424
глава 9
one
оживляем данные
Цодроёно HJ>o
<html> <head> <title>Y ouC ube - The Blog f o r Cube P u z z l e r s < / t i t l e > < s c rip t ty p e = "te x t/ja v a sc rip t"> 11 Конструктор объекта Blog f u n c t i o n B log(body, d a te ) { / / A ssign t h e p r o p e r t i e s ^ t h i s . b o d y = body; t h i s . d a t e = d ate; }
К онст рукт ор В1од() соз■дает два свойст ва блога. Массив обьект ов ■ßlog.
/ / Глобальный массив записей в блог v a r b lo g = [ new BlogC'G ot t h e new cube I o r d e r e d . . " , " 0 8 /1 4 /2 0 0 8 " ), new B lo g ("S o lv ed t h e new cube b u t o f c o u r s e . . . " , " 0 8 /1 9 /2 0 0 8 " ), Ф ункция show BlogQ new Blog("Managed t o g e t a headache t o i l i n g . . . " , " 0 8 /1 6 /2 0 0 8 " ), вы водит за п и си блога new B log("Found a 7x7x7 cube f o r s a l e o n l i n e . . . " , "08/21/2008") под ат р и б ут о м , div.^
];
список записей в блог func;b<^n showBlog (numEntries) { При необходимости редактируем количество записей для показа в сего блога f ( ! num Entries) num Entries = b l o g . l e n g t h ; Если количест во выводимых за ~~ —--------- один раз записей не передано / / Показать записи блога в качест ве аргум ент а, выводим v a r 1 = 0 , b lo g T ex t = ""; все записи. w h ile (1 < b l o g . l e n g t h && i < num Entries) { / / Используйте серый фон для всех остальных записей блога i f ( i % 2 == 0) ----- b lo g T ex t += "<р s t y l e = 'b a c k g r o u n d - c o l o r :#ЕЕЕЕЕЕ'>"; e lse __________ Изменим фоновый цвет записеи b lo g T ex t += "<р>"; блога, чтобы облегчит ь их чтение. / / Генерируем и форматируем HTML-код блога b lo g T ex t += " < strong > " + b l o g [ i ] . d a t e + " < / s t r o n g X b r />" + b l o g [ i ] . b o d y + "</p>' І++;
} 11 Располагаем HTML-код блога на страніdocum ent.getElem entB yld("blog")-innerH TM L = b lo g T e x t;
П о м ес т и м код ■ф о р м а т и р о ва н н о й записи блога под а т р и б у т о м div.
< /scrip t> </head>
Изначально пуст ой ат р и б ут div заполняет ся о т ф о р м а <body onload="show B log(5) ; "> <h3>YouCube - The Blog f o r Cube P u z z le rs < /h 3 > т ированны ми записями. <img s rc = "c u b e .p n g " alt="YouCube" /> ■ 4 Q1V ii d a= <div = "iJ-LUy b l o g ^" Vx//Ud- Li vV x>' < in p u t ty p e = " b u tto n " id = " sh o w a ll" value="Show A l l Blog E n t r i e s " o nclick = "sh o w B lo g ( ) ; " /> </body> ^ </htm l> При щелчке на эт ой кнопке ст ановят ся ~ видимыми все записи блога. далее р
425
бесконечны е «почему» _
Ч асто
^аД аБ аеМ ы е B o T lp o C j, !
Зачем блогу YouCube кнопка Show АН Blog Entries?
Почему для показа записей блога используется свойство innerHTML вместо методов DOM?
Почему объект B l o g не имеет методов?
0 1 Хотя методы DOM и являются пред почтительными с точки зрения совме стимости с веб-стандартам, реализация
что есть более первоочередные задачи, которые следует реализовать, поэтому до
Q ; в текущем состоянии блога эта кнопка действительно не нужна. Ведь у нас всего четыре записи. Но по мере заполнения блога потребуется ограничить количество записей, отображаемых на главной странице. В противном случае загрузка будет занимать слишком много времени. Поэтому по умолчанию показываются только первые пять записей. Кнопка Show АН Blog Entries позволяет вывести все записи на одной странице.
Q ; Их нет на данном этапе. Дело в том,
динамически генерируемого отформати рованного HTML-кода с их помощью будет
методов объекта B lo g мы просто пока не добрались. Но не волнуйтесь. Методы являются существенной частью любого
слишком громозкой. Ведь каждый тег < р >
хорошо сконструированного объекта,
или < s t r o n g > должен быть родитель ским по отношению к узлам с содержимым.
и объект B lo g в этом отношении не исключение.
Свойство же innerHTML позволяет значительно упростить код блога YouCube.
Беспорядочный блог Б л о г Y o u C u b e 1.0 вы гл яд и т х о р о ш о , н о это го н е л ьзя сказать о п о р я д к е его зап и сей . Руби зам ети л а, ч т о в н а с т о я щ и й м о м ен т о н и о т о б р а ж аю т ся в то м п о р я д к е , в к о т о р о м б ы ли с о х р ан е н ы , в то в р ем я как с х р о н о л о г и ч е с к о й т о ч к и зр е н и я п ер в ы м и д олж н ы б ы ть п о к азан ы сам ы е н о в ы е зап и си .
я только что осознала, что не всегда соблюда ла хронологию записей. И теперь у нас проблема!
Самые свежие записи ДОЛЖНЫ показываться первыми.
^
for Cub,
viCube - The Blog for Cube Pu^alers
^
‘ »'140008 Got t e new cube I ordered. Its a rca} peail.
П ользоват ели п ри вы кли в и д е т ь н а вер х у са м ы е свеж ие записи.
s/imom
8 /21/2008 Found a 7x7x7 cube for sale oniine Show A» 3loaEnM»c I Done
426
глава 9
xu That one could be a beast.
оживляем данны е
Необходимость сортировки П р о б лем у с п о р я д к о м за п и с ей м о ж н о р е ш и т ь путем с о р т и р о в к и м асси ва b l o g п о д ате. Т ак как Jav aS crip t п о д д е р ж и в ае т ц и кл ы и ср ав н ен и я , м ы м о ж ет п р о с м о т р е т ь в ц и кл е все зап и си , с р а в н и в и х даты , и о т с о р т и р о в а т ь в о б р ат н о м х р о н о л о ги ч е с к о м п о р яд ке. М еняем м е с т а м и
Blog
э т и две за п и си ,
т а к как вт о р а я оолее свежая. Э т а зап и сь должна о к а з а т ь с я на п е р во м м е с т е , ка к сам ая
О
П р о с м о тр и м м ассив в ци кле.
©
С р авн и м дату каж дого о б 'ь е к 1’а B lo g со следую щ им о б ъекто м .
е
Е сли следую щ ая за п и с ь я в л яется б о лее с веж ей , м ен я ем за п и с и м естам и.
П о д о б н а я с о р т и р о в к а и м е е т с в о и д о ст о и н с тв а и, к аж ется, д о л ж н а н е п л о х о р а б о т а т ь , есл и м ы как следует продум аем п р о цедуру с р а в н е н и я дат.
Подождите! Как нам понять, какая дата более поздняя, если они со хранены в виде строк?
------
Сохраненная в виде строки дата перестает быть датой. И та к , п р и ду м ан н ая н ам и с т р а т е г и я с о р т и р о в к и столкнулась с се р ь е зн ы м п р е п ят с т в и е м . Н е в о зм о ж н о с р а в н и т ь с т р о к и « 0 8 / 1 4 / 2 0 0 8 » и « 0 8 / 1 9 / 2 0 0 8 » и п о н я т ь , какая д ата б олее р ан н я я . Н е т , м ето д и к а с р а в н е н и я с т р о к сущ ествует, н о о н а н е п о м о ж ет нам со п о с т а в и т ь д н и , м есяц ы и годы , с о о т в ет с т в е н н о , в н аш ем случае о н а б ессм ы сленна. З н ач и т , п р еж д е ч ем думать о с о р т и р о в к е , нуж но и зм е н и т ь спо соб х р а н е н и я д ат в блоге.
как вам наши даты?
Объект для gam Руби тр еб у ется т а к о й сп о со б с о х р а н е н и я дат, к о т о р ы й д аст в о зм о ж н о с т ь их д ал ьн ей ш его с р а в н е н и я. Д р у ги м и словам и , д ата д о л ж н а в ес ти себя как дата. А ведь а н а л о ги ч н ы е сл о ва м ы го в о р и л и в отнош е- Д а т а п ервой НИИ объекта! И д ей с тв и те л ь н о , в Jav aS crip t сущ;ествует в с т р о е н н ы й Записи в 5лог. о б ъ е к т D a te , в п о л н е п о д х о дящ и й д ля н аш и х нужд.
Д а та
^
Л
Г
М ет оды з а дания даты.
і М ет оды У п олучения дат ы .
Встроенный объект Date представляет некий момент времени.
О б ъ е к т D a te п р е д с та в л я е т о п р е д е л ен н ы й м о м е н т в р ем ен и , в ы р а ж е н н ы й в м иллисекундах, и я в л я е т с я с т ан д а р т н о й ч астью Jav aS cript. Х отя с в о й с т в а это го о б ъ е к т а и исп ользую тся, вам о н и н е видны . П о это м у р а б о т а с о б ъ ек то м D a te осущ ествл яется и с к л ю ч и те л ьн о ч е р е з его м етоды . О б ъ е к т D a te , к ак и р а н е е о б ъ е к т B lo g , со зд ается п р и пом ощ и о п е р а т о р а new. В от п р и м е р с о зд ан и я об ъ екта, п р ед ставл яю щ его текущ унздату и врем я.
С охранение — -
о б ъ ект а p a te в перем енно й .
var
С оздание о б ъ е к т а P a te п ри п ом о щ и
Время внутри объекта Date выражено в миллисекундах.
глава 9
=
new
DateO;
Новый о б ъ ек т P a te . предст авляет т е к у ' щуьо д а т у /в р е м я .
о п ер а т о р а new .
Д а т а пер ед а ет ся к о н с т р у к т о р у jв виде т екст о во й ст р о ки .
428
now
Э то т о б ъ ек т D a te со зд ан и и н и ц и а л и зи р о в а н с текущ им и д ат о й и врем енем . О б р ат и т е вн и м ан и е н а то, ч то син такси с н ап ом и н а е т вы зов м етод а и л и ф ункц ии, так как вам п ри ход и тся вы зы вать ко н структор об ъ ек та D a te . К онструктору в кач естве аргум ента м о ж н о п е р е д а ть строку с д ато й , о т л и ч н о й о т текущ ей. С каж ем , в о т о б ъ е к т D a te с д ат о й п е р в о й зап и си в блоге Y ouC ube:
v a r blo gD ate = new D a t e ( " 0 8 /1 4 /2 0 0 8 " ) ;
оживляєм данны е
Вычисление времени О д н и м и з сам ы х б о льш и х д о ст о и н с тв о б ъ е к т о в я в л я е т с я и х с п о со б н о сть у п р ав л я ть сво и м со с то я н и е м . Н а п р и м е р , п р е д став ьте , как сл о ж н о бы ло бы вручную в ы ч и с л я т ь к о л и ч е с т в о д н е й меж ду двумя датам и. П о т р е б о валось бы п р е о б р а зо в а т ь дату в д н и с и зв е с т н о й т о ч к о й о т с ч ет а , а такж е учесть, ч т о с н ач ал о м года н а ч и н а е т с я н о в ы й ц и к л о тсч ета. П оэтом у мы отдад и м эту задачу н а откуп о б ъекту D a te . П о с м о т р и т е , к ак л егко он П р е о б р а зо в а с н е й сп р ав л яется: Э т а ф ун кц и я п р и н и м а е т в к а ч е с т ве а р г у м е н т о в два о б ъ е к т а D a te.
function getDaysBetween(datel,
date2)
var daysBetween = <date2 - datel)
ние м и л л и се к у н д о секун ды , з а т е м о м и н у т ы , часы и наконец в дни!
{
/ (1000 * 60 * 60 * 24);
return Math, round (daysBetween) ; }
В е р н е м р е з у л ь т а т п о сле округл ен и я ... М е т о д ro u n d Q п ринадлеж и т о б ъ е к т у Ма±!л, с к о т о р ы м м ы ещ е п о зн а к о м и м с я в э т о й гл а ве.
getDaysBetween(datel, date2);
аж нш е
Э т о т п р о с т о й , но м ощ ны й код д е л а е т всю р а б о т у!
Д а н н а я ф ун кц и я д ем о н с тр и р у ет нам , н аск о л ьк о м ощ ны м я в л я е т с я о б ъ ек т D a te , н а п р о с т о м ф р а гм е н т е код а —в ы ч и та н и и . С л о ж н ы е в ы ч и с л ен и я р а зн и ц ы меж ду двумя д атам и ск р ы т ы вн утри о б ъ ек та. Н ам в ы д ается р езул ьтат в ы ч и т а н и я , п р ед с та в л я ю щ и й с о б о й к о л и ч е ст в о м иллисекунд между указан н ы м и датам и. Д о с т а т о ч н о п р е о б р а зо в а т ь м ил лисекун ды в д н и и о кругл и ть резу л ьтат —и у нас под рукой п о л е зн ей ш а я ф у н к ц и я , которую м ож н о вы зы в а ть в ся к и й р а з в п о д о б н ы х случаях.
Создайте два объекта D a te для первых двух записей блога YouCube. Затем при помощи функции g e t D a y s B e t w e e n () вычислите, с каким промежутком они написаны, и выведите результат в отдельном окне.
далее >
429
реш ение упражнения
Jjfe«V
Вот как при помощи функции g e t D a y s B e t w e e n () вычислить промежуток
ТП ТраЖ Н бН И б
первыми записями в блоге, которые представлены при помощи
?еш ш е Создание о б ъ е к т а P a te для двух зап и сеи ■ блога. Щ Г Ы 9 3 Р .Ш .^ ..Т .
К
var^ bJoßP ateZ ,~ n ew _ P a t e ( " 0 8 / 1 <R/Z008"); .^.y..t. 0 f :'tp ^ y s ß e tw e e n (h lo g P a te l, blogP ateZ ) + " days.");
Ф ункция ( в о з в р а щ aа eе m т
разн иц у-
I J
The dates are separated by S days.
А б а о б ъ е к т а P a te п ер ед а н ы ф ун кци и о к а ч е ст ве аргум ен т ов.
f~ 0 iT 3
Пересмотр gam В блоге Х отя м ы и п о зн а к о м и л и с ь с о б ъ ек то м D a te , п о зво л яю щ и м л е гк о у п р ав л ять датам и , д аты в наш ем о б ъ е к т е B l o g п о к а ещ е со х р а н е н ы в ви д е стр о к. А зн а ч и т , в о с п о л ьзо в а ться п реи м ущ е ствам и , к о т о р ы е нам д ае т о б ъ е к т D a te , м ы м ож ем т о л ь к о п осл е п р е о б р а зо в а н и я дат.
Дата
Блог
Got the new cube I ordered. It’s a real pearl."
С во й ст во d a te о б ъ е к т а Blog нужно п р е о б р а зо в а т ь из ст роки в объект P a te .
"08/ 14/ 2008"
В о п р о с в том , м ож н о л и в св о й ств е d a t e о б ъ е к т а B lo g х р а н и т ь о б ъ е к т D a te вм есто строки ?
430
глава 9
оживляем данные
Объект Внутри другого объекта Н а п р и м е р е н аш его бло га м ы увидим , как о д н и о б ъ е к т ы м огут с т ан о в и т ь с я к о н т е й н е р а м и для других. У о б ъ е к т а B lo g есть два сво й ств а, к о т о р ы е , в свою о ч ер е д ь , я в л я ю т ся о б ъ е к там и S t r i n g . О н и н е в ы гл яд ят к ак о б ъ ек ты , п отом у ч т о со зд аю тся как л и т е р а л ы , п р о с т ы м ц и т и р о в а н и е м с т р о к и тек ста. О б ъ ек т ы D a te н е столь ги б ки и потом у со зд аю тся п р и п о м о щ и о п е р а т о р а new.
С т р о ко вы й л и т е р а л авт ом ат ически со зда е т о б ъ е к т S trin g .
Ч т о б ы со зд ать св о й с тв о б л о га d a te в ви д е о б ъ е к т а D a te , нам то ж е п о тр еб у ется о п е р а т о р new, к о т о р ы й сф о р м и р у е т н о в ы й о б ъ е к т О б ъ е к т Blog создает ся в п р о ц е с с е со зд ан и я о б ъ е к т а B lo g . Э то о п и с ан и е м о ж ет звучать о п е р а т о р о м n ew . пугаю щ е, н о код в ы гл яд и т д о ст а т о ч н о п р о сто . iiC.------
v a r b lo g E n try = new Blog("N othing going on b u t t h e w e a t h e r . " . new D a t e ;
1 0 /3 1 /2 ,0 0 8 "));
V Э то т код п о к а зы в а ет, каким о б р азо м зап и сь в б л о ге Y o u C u b e со зд ается в виде о б ъ екта, со дер ж ащ его два други х о б ъ ек т а ( S t r i n g и D a te ). Р азум еется, для п о л н о й и м и та ц и и б ло га нам п о тр еб у ется м ассив о б ъ е к т о в B lo g .
Блог
Строка
С во й ст во b o d y.
О б ъ е к т D a te со зда ет ся и п ередает ся кон ст рукт о ' р у вЪ дО т акж е п р и п о м о щи о п е р а т о р а n ew .
Оператор new создает объекты с помощью конструктора.
С войст во d ate.
Возьми в руку карандаш Перепишите код создания массива объектов B lo g с учетом того, что каждая дата теперь является объектом D a te . Текст записей давайте в сокращенном виде.
далее ►
431
реш ение упражнения
Возьми в руку карандаш 'ешение
Вот ка к вы глядит код создания массива объ ектов B l o g с уч е том того, что каждая дата теперь является объ е ктом D a te .
Все записи до сих п о р со зд аю т ся как о б ъект ы Blog. . К‘?.^Г.к{93.г.. .
[
Blp.e(,“. 9 p . t . t h f . 9.4'^р.. !
.
. ne w i ^ a t e ( " 0 8 / ^ 4 / 2 0 0 8")),
b u t o f co u rse...“, n e w D a te ( " O S /l я /Z O O 8")), ^ h e a d a c h e toiling...", n e w D a te ( " 0 8 / 1 6 /Z 0 0 8 " ) ) , n e w BlogC’Found a 7 x 7 x 7 cu be fo r sale...", n e w D a te ( " 0 8 /Z X /Z 0 0 8 " ) ) ]■
......................................... ........................ С т роковы е л и т е р а л ы п р екр а сн о подходят для п р е д с т а вле н и я т е к с т а зап и сей блога.
J
А а т а для каждого об ъект а -B lo g т е п е р ь создает ся как о б ъ ект Date.
/
_
ча а в о
■ ^аД аБ аеМ ы е
‘
Б о г ц р 'о с ь ! Почему даты в объекте D a t e сохраняются в миллисекундах?
! Ну, во-первых, объект D a t e представляет некоторый момент. Если бы для вселенной можно было нажать кнопку Pause, мы получили бы такой момент. Но чтобы объяснить другим людям, когда случился этот момент, требуется некая точка отсчета. В качестве такой точки выбрано 1 января 1970 года. Теперь нужно показать сдвиг относительно этой точки Пусть он будет равен 38 годам, 8 месяцам, 14 дням, 3 часам, 29 минутам и 11 секундам. Но это слишком громоздкий способ представления данных. Проще выбрать единицу измерения, которая в состоянии представить самую маленькую долю.
КЛЮ ЧЕВЫЕ МОМЕНТЫ
ш
■
Именно поэтому мы пользуемся миллисекундами, и вместо набора различных единиц у нас появляется 1,218,702,551,000 миллисекунд. Да, это много, но иауаЗспр! умеет работать с большими числами.
Должен ли я вручную преобразовывать миллисекунды при работе с объектом D a te ?
Q ; Зависит от ситуации. Объект D a t e снабжен набором методов, умеющих извлекать значимые части, что избавляет вас от необходимости иметь дело с миллисекундами. Но, если нужно определить разницу между датами, от миллисекунд вам никуда не деться.
*їч
Стандартный объект D a t e представляет момент
Объект D a t e умеет совершать математические
времени, выраженный в миллисекундах.
операции с датами и даже сравнивать их друг
Объект D a t e снабжен методами доступа к различ ным фрагментам даты и времени.
с другом. В отличие от объекта s t r i n g объект D a t e созда ется при помощи оператора ne w .
432
глава 9
оживляем данные
Бесполезные даты П р е о б р а зо в а в св о й с тв о d a t e о б ъ е к т а B lo g в о б ъ ек т D a te , Руби п р и го т о в и л а с ь вплотную за н я т ьс я с о р т и р о в к о й зап и сей . Н о о н а столкнулась с н о в о й п р о б л е м о й —д аты вы гл яд я т ч е р е с чур сл о ж н о . Руби п о д о зр е в а е т, ч т о ч и т ат е л я м б л о га н е важ н а и н ф о р м а ц и я о в р е м е н н о й зо н е , в к о т о р о й о н а н ах о д и тся, и это будет о т в л е к а ть их. И так, нам нуж но б о л ее д етал ьн о р ассм о т р е т ь проц едуру встав к и в бло г о б ъ е к то в D a te !
Д а т ь / записей
слишком громоздки и дают избыточную информацию!
YouCube - The Юоа for C ube ^uzziers
YouCube - The Blog for Cube Pim lm
----Thu Aeg 14 7 Ш Got Ле new cttbe I orfcKd. It s a ю й peari.
« I «РРІ.Ї
Ввод объекта Date имел смысл, но результат выгля дит ужасно. Не помню, чтобы я программировала подобное форматирование.
Found a Show All
BtoaEntries
Done
Д ело не только
в ужасно выглядящ их дат ах. З ап и си
блога все еш,е не упорядочены!
Руби о за д ач е н а с тр ан н ы м ви д о м дат в бло ге Y o u C u b e, ведь о н а н е п и сал а ко д а д ля о т о б р а ж е н и я и х в п о д о б н о м виде. О н а всего л и ш ь п р е о б р а зо в а л а с т р о к и с д атам и в о б ъ ек ты D a te . Н еу ж ел и эт о за го в о р зл ы х сил JavaS cript?
далее >
433
должен быть другой способ
Преобразование объектов 8 т е к с т к счастью , эт о н е зл ы е си л ы нуж но о б в и н я т ь в б езо б р азн о м ви д е дат. Б о л е е то го , эт о о б ы ч н о е п о в е д е н и е о б ъ е к то в Jav aS crip t, о т в еч аю щ и х за ф о р м а т и р о в а н и е дат, - т о е с ть даты ф о р м ат и р у ю т ся автом ати ч ески ! Э то р а б о т а е т следую щ им об разом : все о б ъ е к т ы Jav aS crip t обладаю т м ето д о м t o S t r i n g ( ) , о б есп еч и в аю щ и м и х те к с т о в о е п р ед ставл ен и е. И н аш и д аты я в л яю тся р езу л ьтато м д е й с тв и я м етод а t o S t r i n g () о б ъ ек та D a te .
v a r blogD ate = new D a t e (" 0 8 /1 4 /2 0 0 8 " ); a lert(b lo g D ate.to S tr in g {
П р о б л е м а в том , ч то м етод t o S t r i n g () ав т о м а т и ч е ск и ср аб а т ы в ае т , когда о б ъ е к т и сп о льзу ется в м есто стр о к и . Н а п р и м е р , код в ы зо в а всп л ы ваю щ его о к н а с д ат о й за п и си м о ж н о н а п и с ать в о т так, получив т о т ж е сам ы й результат:
Thu Atig 14 2008 00-00:00 CMT-0500 <COT)
М ет од to S trin q O п о ка зы ва ет , каким Образом о б ъ ект P a te с лед и т за вр ем ен ем .
a lert(b lo g D ate);
М ет од to S trin g O не т о ль к о д ает ст рокодое п р е д с т а влен и е дат ы , но п о я вля ет ся и в дру ги х объект ах.
Метод toString () обеспечивает строковое представлепие объекта. 434
глава 9
Т ак как ф у н кц и я a l e r t () п р и н и м а е т в кач естве аргум ента с т р о к и , о б ъ е к т D a te зн а ет , ч то ему н ео б х о д и м о п р е о б р а зо в а н и е в д ругой ф о р м ат . Д л я эт о го о н с ам о сто я т е л ь н о в ы зы в а ет м етод t o S t r i n g ().
Д е й с т в и е м ето д а t o S t r i n g ( ) н е стал о бы п р о б л ем о й , есл и бы д аты о т о б р а ж ал и сь в п р о с т о м ф о р м а т е , н а п р и м е р MISl/ Д Д / ГГГГ. Т о есть н аш блог Y o u C u b e н е м о ж ет в о с п о л ьзо ваться пр еи м у щ еством зад ан н о го по ум олчан и ю п р е д ста в л ен и я строк.
оживляем данные
Д оступ к ф рагментам даты Руби нуж ен сп о со б р егу л и р о в к и ф о р м а т а даты . Д л я эт о го нам п о тр еб у ется доступ к о тд ел ьн ы м ф р а гм е н та м , а и м е н н о к м еся цам , д н ям и годам . П о сл е ч его м ы см ож ем с о б р а т ь дату нуж ны м нам о б р азо м . К счастью , о б ъ е к т D a te о б л ад ает всем и н ео б х о д и м ы м и д ля эт о го м етодам и.
М есяц п р е д с т а в л я е т с я о биде числа о т о до ц .
Дене> — э т о число
о т 3- до 3 1 .
J
Год в полной ф о р лле (6 виде 4 с и м волов).
Обратите внимание на значения, возвра|Ды»е I щаемые методами осшо]зожНь1! объекта Date.
О б ъ е к т D a te о б л ад ает н е т о л ь к о т р е м я в ы ш еуказанны м и , н о и други м и м ето д ам и , обеспечиваю ш ;им и р а зл и ч н ы е сп о со б ы д оступа к д ат е и в р ем ен и . О д н ако д ля н аш и х ц е л е й вп о л н е д о с т а т о ч н о эт и х тр ех .
Метод getMonthQ возвращает месяц в виде чисел от О (январь) до 11 (декабрь), в то время как метод getDateQ возвращает число в диапазоне от 1 до 31.
возьми в руку карандаш Устраните проблему с записью дат в блоге YouCube, пере писав код, форматирующий запись блога и сохраняющий его в переменной b lo g T e x t . Убедитесь, что даты имеют формат ММ/ДД/ГГГГ. Вот исходная версия кода: blogText
+=
"<strong>"
+ blog[i].date
+
"</strongXbr
/>"
+ blog[i].body
+
"</p>";
далее >
435
реш ение упражнения
- ^ з ь м и В руку карандаш Решение
Вот как выглядит в результате переписанный код, форма тирующий запись блога и сохраняющий его в переменной Ы o g T e x t.
b lo g T e x t + - "< s tro n g > " + b l o g [ i ] . d a t e
.
+ " < / s t r o n g X b r /> " + b l o g [ i] . b o d y + "< /p > "
.t.T. "M r.o n e? ". r.
.t. i .) .+
+-
h logliJ.date.getF u llY earQ + " < /s tr o n g x b r /> " Д л я получения нуж ного ф о р м а -
b lo g [ i] .b o a y + "< /p y "-,
т а произведем ф орм ат ирование о б ш к т а D a te бручную .
К а ж д ы й ф р а г м е н т дат ы и зв л е к а е т с я из о б ъ е к т а D a te п р и п о м о щ и с о о т -
Д а т а т еперь от оС раж ает ся в п ри вы чф орм ат е М М /
вет ст вую щ его м ет о д а.
А Д /Г Г Г Г .
Д а т ы упроцаю т сортировку Т еп е р ь , когда д аты в бло ге п р е д с та в л е н ы в ви д е о б ъ е к т о в D a te , ч то лучш е о т в е ч а е т н аш им целям , в е р н е м с я к воп р о су о п о р я д ке за п и с ей . В настояш ,ее в р е м я о н и о т о б р а ж аю т ся в том п о р я д ке, в к о т о р о м о к азал и сь с о х р а н е н ы в м асси ве Ы о д , в то в р ем я как нам тр еб у ется, ч то б ы сам ы е св еж и е за п и с и б ы ли наверху. Р ассм о тр и м еш;е р а з п р оц едуру с о р т и р о в к и :
Д ата
Т е п е р ь у нас е с т ь , О б ъ е кт ы D a t e , к о ^поры е м о ж н о с р а в н ит ь друг с другом .
О
П росм отрим массив в цикле.
©
С р авн и м дату каж до го о б ъ е к т а B l o g со следую щ им.
е
Е сли следую щ ая за п и с ь я в л я е т с я б о л ее св еж ей , м ен яем зап и си м естам и.
Х о тя б л аго д ар я об ъ екту D a te т а ч асть с т р а т е г и и , к о т о р а я о т н о с и т ся к с р а в н е н и ю дат, стал а вы гл яд еть м ен ее устраш аю щ ей, о стал ьн ая ч ас т ь п л ан а все ещ е т р еб у ет н а п и с а н и я и зр я д н ы х ф р а гм е н т о в кода. С д ругой с т о р о н ы , н е в о зм о ж н о п о в е р и ть , ч то б ы т а к а я п р о б л ем а, как с о р т и р о в к а н а б о р о в д ан н ы х , н е р еш ал ась м н о го р а з до этого. А зн а ч и т , и зо б р е т а т ь в ел о си п ед л и ч н о вам н е потребуется...
436
глава 9
оживляем данные
А здорово было,бы если бы в JavaScгipt была встроенная функция для выполнения рутинной работы по сортировке данных...
далее *
437
сорт ировка своими силами
Массивы как объекты К ак вы дум аете, м о ж е т л и м ассив сам себ я с о р т и р о в ать ? Э то п р е д п о л о ж е н и е не л и ш е н о см ы сла, в к о н ц е ко н ц о в , д ан н ы е ж е ум ею т сам о с т о я т е л ь н о о сущ ествлять п р е о б р а зо в а н и е в с т р о к о в ы й ф о р м ат . Н о ч то б ы т а к о е стал о в о зм о ж н ы м , м ассив д о л ж ен б ы ть о б ъ ек то м и об ла д ать соответству ю щ и м и м етод ам и. С ам ое и н т е р е с н о е , ч т о т а к о н о и есть. П о м н и те код и з с ц е н а р и я M an d an g o ?
Массив это всего лип1ь объект
f o r (var i = 0; i < s e a t s . l e n g t h ; 1++) {
le n g th — э т о с в о й ст в о м а сси ва п редост авляю щ ее и н ф о р м а ц и ю ' о к о л и ч е ст в е э л е м е н т о в в нем .
Переменная se a ts я вляет ся м ассивом .
И та к , м ассивы я в л яю тся о б ъ ектам и . О зн а ч а е т л и это , ч то о н и м огут с о р т и р о в а т ь себя сами? М ассивы о б лад аю т н е т о л ь к о с во й ством l e n g t h , н о ещ е и м ето д ам и о б р а б о т к и св о и х д ан ны х. В том чи сл е и м ето д о м s o r t ( ) , к о т о р ы й нам нуж ен. П о см о тр и м , как и м е н н о о н р аб о тает.
nums
(С о р т и р о в к а
по в о зр а с т а н и ю .
М етод s o r t () м е н я е т п о р я д о к эл е м е н то в вн утри м ассива. П о ум олчани ю с о р т и р о в к а осу щ ествл яется п о в о зр астан и ю , п о э т о му м ассив nums п р и о б р е т е т в о т т а к о й вид:
438
оживляем данные
Пользовательская copmupoBka З а д а н н о го п о ум олчан и ю п о в е д е н и я м ето д а s o r t () о б ъ е к та A r r a y ч ас т о н е д о с та т о ч н о . Н о н а п о м о щ ь п р и х о д и т т о т ф акт, ч т о п р о ц ед у р а с о р т и р о в к и о п р е д е л я е т с я ф у н к ц и ей с р а в н ен и я , котор у ю в ы зы в а е т м ето д s o r t ( ) . З н а ч и т , вы м о ж ете п о в л и я т ь н а с о р ти р о в ку , н ап и сав св о й в а р и а н т э т о й ф у н кц и и . В от как о н а о б ы ч н о вы гляд ит:
в
f u n c t i o n compare (X, у) { r e t u r n X - у;
ка чест ве
а р гум ен т о в
в ы с т у п а ю т два э л е м е н М ассива, к о т о р ы е сю а вн и ва ю т ся с целью с о р т и р о в ки .
В о зв р а щ а е м о е значение оп ределяет , ост анут ся ли к и у на свои х м е с т а х или же п о м е н я ю т с я д р у г с д р у го м .
Ф ункция c o m p a re () в о зв р а щ ае т ч и сл о , о п р ед ел яю щ ее р езульти рую щ ее п о л о ж ен и е X и у.
< О П о ст ав и м X п е р е д
Сортировка не нужна, оставим элементы на местах.
__ > 0
П о ст ав и м у п е р е д н.
Н а п и с а н н а я ф у н кц и я c o m p a re () в став л я ется в ур авн ен и е с о р т и р о в к и м асси ва п р и в ы зо в е м ето д а s o r t () —д о ста то ч н о п е р е д а ть ссы лку н а н е е этом у методу.
nums. s o r t (compare) ;
С о р т и р о в к а м асси оа т еперь у п р ав л я е т -
„дЯмсйННОМ ва м и ф ун кц и ей со т р а геО -
Возьми В руку карандаш Напишите код для функции c o m p a re ( ) , располагающей массив записей блога YouCube в обратном хронологическом порядке. Подсказка: вычитание объектов B lo g друг из друга осуществляется при помощи обычного знака минус.
далее >
439
реш ение упражнения
Возьми в руку карандаш Решение
Вот как выглядит код функции c o m p a re ( ) , располагающей массив записей блога YouCube в обратном хронологическом порядке.
.f u n c t i o n c p m p a r e j^ h iq g x r e t u r n h lo g Z .d a t e - b lo g t . d a t e ;
являю т ся о б ъ е к т ы B lo g , в е д ь и л 1\е и н о и з HWX с о с т о и т
} ........ (
^
В ы чит ание первой дат ы
рт и ровке в обрат ном хр о н о л о ги ч еск о м п орядке.
.
(м и лли секин ды ) с-^^кунш).
Упрощение сортировки Н а п и с а н н а я н ам и ф у н кц и я с р а в н е н и я эл е м е н т о в м асси ва и с пол ьзу ется и с к л ю ч и те л ь н о в м ето д е s o r t (). А зн а ч и т , и м ен о в ан н ая ф у н кц и я нам в д ан н о м случае н е тр ебуется. П о м н и т е л и т е р а л ы ф у н кц и и д ля т е р м о с т а т а , с к о т о р ы м мы р а б о т а л и в гл аве 6? Ф ункция c o m p a re () т ак ж е я в л я е т с я п р е в о с х од н ы м кан ди дато м н а эту ро л ь. Б о л е е т о го , с о р т и р о в к а за п и се й б ло га у п р о сти тся , есл и эту ф ункц ию п р е в р а т и т ь в л и т ер а л , н е п о ср е д с тв е н н о п е р е д а в ае м ы й м етоду s o r t ().
Ы о д . s o r t ( f u n c t io n ( b l o g l , Ыод2) r e tu r n b lo g 2 .d a te - b lo g l.d a te ;
{
'п осредст венн о м е т о д у s o r tQ м а сси ва .
}) ;
К ак л ю б и т е л ь го л о во ло м о к . Руби н а п е р в о е м есто ста в и т эф ф е к т и в н о с т ь . А у д ал ен и е н ен у ж н о й и м ен о в а н н о й ф у н кц и и у в ел и ч и в ает эф ф е к т и в н о с т ь м ето д а s o r t (). К р о м е то го . Руби н е п о н и м а е т, зач ем ф у н кц и и с р ав н е н и я ц ел ы х т р и с т р о ч к и кода. Н аш л и т е р а л д о ст а т о ч н о п р о с т , ч то б ы о б о й т и с ь всего о д н о й с т р о ч к о й .
Л и т е р а л ф ун кци и со к р а т и л с я до одной ст р о ч к и кода. -
b l o g . s o r t ( f u n c t i o n ( b l o g l , Ы од2)
440
глава 9
'
J
{ r e tu r n b lo g 2 .d a te - b lo g l.d a te ;
оживляем данные Ч а с зц о
<аДаБаеМые БоЦ РоС ь!
Любой ли объект обладает методом t o S t r i n g () ?
Каким образом функция сравнения работает с объектами D a te objects?
; Да. Даже если вы создадите специальный объект, не снабдив его
; Функция сравнения возвращает число, значение которого отвечает
методом t o S t r i n g ( ) , JavaScript по крайней мере укажет на существование такого объекта при попытке использовать
за сортировку двух аргументов. При сравнении дат нужно, чтобы более поздняя дата шла впереди. Более
его там, где требуется строка. В некоторых случаях строки не имеют особого значения, но вы можете по своему желанию добавить объекту
поздняя дата больше, поэтому определить порядок следования можно
метод
при помощи обычного вычитания. Вторая дата оказывается перед первой только при условии, что она больше (результат
t o S t r i n g ( ) , чтобы получить
вычитания больше 0).
возможность читать его значение.
3» Как метод A r r a y . s o r t ( ) определяет, использовать ему пользовательскую функцию сравнения или функцию по умолчанию? ; Это решение зависит от того, был ли функции s o r t ( ) передан аргумент. Отсутствие аргумента означает сортировку по умолчанию. Его наличие интерпретируется как ссылка на функцию и используется как основа для сравнения сортируемых элементов. То есть ссылка на функцию сравнения является необязательным аргументом.
Счастье Руби Б л о г Y o u C u b e п о с т е п е н н о п р и б л и ж а е тс я к п р ед ставл ен и ям Руби об и д еал ьн о м м есте о б щ е н и я с други м и п о к л о н н и к а м и гол ово ло м о к. Й 0 0
С b ^ h e jlo g
^
_______ _____
Я люблю свой блог почти так же, как головоломки!
T o u C u b c - The Btog for Cube P u lle rs
m io m ^ Found a 7x7x7 cube for sate
YikesS That one could be a beast.
8Solved /19/2008 fee new cube but of couise get a headacte »ilfflg over
I’m bored and shopping for a new one.
new cubc. Gotta nap.
Got (he new cube I oidcnd. It's a red pearl. Show Ail Й 09 Entries Done
________
-Д д ть / им ею т п о н я т н ы й вид.
П оследние з а п и си в ы в о д я т с я на с а м о м верху.
далее *
441
головоломка «п оиск слова»
Поиск БлогУ ои С иЬ е п р е к р а с н о р а б о т а е т , н о н е к о т о р ы е п о л ьзо в а т е л и заго в о р и л и о т а к о й ф у н кц и и , как п о и с к п о всем зап и сям . Т ак как Руби п л ан и ру ет п и сать туда ч асто и м н о го , о н а согласн а, ч т о эт о к р а й н е п о л е зн а я ф у н кц и я, о с о б е н н о в д о л го с р о ч н о й п ер сп ек ти в е.
Search the Мод j 7x7x7
в в ед ен н а я с т р о к а и с п о л ь з у е т с я для п о и с ка п о в с е м у т е к с т у
Руби нуж ен п лан п о р е а л и за ц и и п о и ск а в блоге Y ouC ube... Н е п ом огут ли ей в это м объекты ?
442
глава 9
оживляем данные
Поиск по АлассиВу Ф ункция п о и с к а в блоге Y o u C u b e вкл ю ч ает в себя ц и к л и ч е с к и й п р о с м о т р м асси ва всех за п и с ей и п о и с к совп ад аю щ и х си м вол ов в каж дой и з них.
Ц иклический просмотр всех записей.
Эта конструкция имеет смысл, но как найти слово в тексте записи? Я озадачена... но, кажется, выход есть!
О
Выход и з цикла в случае совпадения.
Ш Т У РМ Как бы вы реализовали поиск среди записей блога YouCube совпадающей строки текста?
далее *
443
свяжем их вместе
Как вы уже знаете, строка — это объект. Так может быть, строка сама может осуществлять поиск?
Строка как объект, доступны й для поиска. В озм ож н о, вы уже п о н ял и , ч т о о б ъ ек ты в Jav aS crip t везде. И с т р о к и т о ж е я в л я ю т ся о б ъ ек там и и снаб ж е н ы м н о го ч и с л ен н ы м и м ето д ам и для в заи м о д ей стви я с т е к ст о в ы м и д ан н ы м и . О д и н и з эт и х м етод ов д ей с т в и т ел ь н о п о зв о л я е т и ск ать в с т р о к е ф р агм ен т ы текста.
Поиск в с т р о к е п о сл ед о в а т ел ь н о с т и си м вол ов.
“G o t th e n e w c u b e 1 o rd e re d . It ’s a re a l p e a rl."
Ч исло си м во л о в в ст р о к е.
444
глава 9
О п р е д е л ен и е м ест а в с т р о ке ук а за н н о го си м во л а .
П реобразовани е с т р о к и 8 нижний и верхн ий р е г и ст ры со о т вет ст вен н о.
оживляем данные
М етод indexOfO М етод in d e x O f () п о зв о л я е т и ск ать в о б ъ е к т е S t r i n g ф р а гм е н т ы текста. П о и с к о в ы й за п р о с п е р е д а ет с я м етоду как аргум ен т —так как м ето д п р и н а д л е ж и т об ъ екту S t r i n g , других аргум ен тов п е р е д авать н е нуж но. М етод i n d e x O f ( ) в о зв р а щ ает и н д ек с, указы ваю щ и й н а м е с то п о л о ж е н и е о б н ар у ж ен н ы х си м вол ов, и л и -1 , если п о и ск о к азал ся безуспеш ны м .
v a r s t r = "Got th e new cube I o r d e r e d . I t ' s a r e a l p e a r l . " ; a l e r t ( s t r . i n d e x O f ( " n e w " ) );
Ч т о б ы п о н я т ь , откуда п о я в и л а с ь ц и ф р а 8, р а с с м о тр и м строку как м ассив о тд ел ь н ы х сим волов.
10
, , , , , , , , , I Ml
20
1111 м m
30
40
i l l м I i l l i l l 11111 i 11 i I I I
"Got the new сгдЬе I ordered. It's a real pearl." К аж дому с и м в о л у в с т р о ке с о о т в е т с т в у е т у н и к а л ш ы й индекс. О т с ч е т
П о и с к о в ы й за п р о с n e w n o я в л я е т с я в с т р о к е под и н ~
д е кс о м 8.
Если нуж ной п о с л е д о в ат е л ь н о с т и с и м в о л о в в с т р о к е н е существует, м етод in d e x O f () в о з в р а щ а е т -1 .
начинает ся с О, ч т о началу ст р о ки .
соот вет ст вует
В р е з у л ь т а т е п о л у ч а е м —I ,
v a r s e a r c h ln d e x = s t r . i n d e x O f ( " u s e d " ) ;
аВаЖ еН Ие ^
^ |Ь а ж н (
/^ < ^ ^ J < KaK с т р о к а п о и с ка не Нйм^енй 6 о б ъ е кт е S t r in g .
показана любимая загадка Руби. Определите индекс каждого вхождения подстроки «cube» в строку загадки.
«Кубистка возводила в куб два куба и получила восемь. Была ли она кубинкой?»
далее *■
445
реш ение упражнения
__ 13Ж Н2НИ2
Вот индексы вхождения подстроки « c u b e» в любимую загадку Руби. «Кубистка возводила ^ получила восемь. Была ли она кубинкой?».
деке о .
"A cubist cubed two cubes and ended up with eight. Was she Cuban?" И н д е к с вхоукдения^ подст роки
Я.
V _ И ндекс вхождения подст роки
Поиск по блогу Б л а го д а р я м етоду in d e x O f () п о и ск п о с тр о к ам в ы п о л н я е т ся д о с т а т о ч н о п р о с т о , н о у Руби для п о и с к а и м ее т с я ц ел ы й блог. О н а с о б и р а е тс я в ц и кл е п р о с м а т р и в а т ь все за п и с и и н а каж дой и т е р а ц и и и с п о л ь зо в ат ь м ето д i n d e x O f ( ) . О б н ар у ж ен н ы е со в п а д е н и я д о лж н ы в ы в о д и ть ся в о тд ел ьн о м окн е. П е р е д тем как п р и сту п и ть к н а п и сан и ю ф у н кц и и п о и с к а по блогу, нам п о тр еб у ется со зд ать т е к с т о в о е пол е, в к о т о р о е будут в во д и ться п о и с к о в ы е за п р о с ы , и кнопку, запускаю щ ую пои ск.
< i n p u t t y p e = " b u t to n " i d = " s e a r c h " v a l u e = " S e a r c h t h e B log" o n c l i c k = " s e a r c h B l o g ( ) /> < i n p u t t y p e = " t e x t " i d = " s e a r c h t e x t " n a m e = " s e a r c h te x t" v a lu e = " " /> Д о с т у п к п о и ско во м у за п р о су о с у щ е ст в ля е т с я через IP se a rc h te x t.
Поисковый запрос!
Э т а кнопка вы зы вает ф ун к ц и ю $еагскВ Ь д() и т е м са м ы м и нициирце т п о иск по блогу.
Search the Blog ||7x7x7
Т е п е р ь , когд а п о и ск о в ы е Н Т М Ь -элем ен ты н а м есте, остал о сь н а п и с ать код ф у н к ц и и з е а г с Ь Ы о д ( ) . Т ак как д ля о т о б р а ж ен и я р езу л ьтато в п о и с к а эт а ф ун кц и я и сп ользует в сп л ы ваю щ ее окн о, о н а н е в о зв р ащ ае т н и к а к о й и н ф о р м а ц и и . А т а к как п о и ск о в ы й за п р о с с ч и ты в а е т с я и з т е к с т о в о го п ол я, в к о т о р о е его ввел п о л ь зо в ател ь, нам н е п отреб ую тся и н и к ак и е аргум енты .
446
глава 9
оживляем данные
Магниты JavaScript Функция зе а г с Ь В 1 о д () отвечает за циклический просмотр записей блога и поиск текста, совпадающего с поисковым запро сом. Помогите Руби закончить код, поместив магниты на пустые места. Подсказка: совпадающие результаты поиска должны ото бражаться вместе с датой записи в виде ММ/ДД/ГГГГ, выводимой в квадратных скобках после текста блога.
function
searchBlogO =
{ " ) .value;
d o c u m e n t . g e t E l e m e n t B y l d ("
var for
(var
1 = 0 ;
//
Проверяем,
if
(blog[i]. a l e r t e ["
; i ++)
i < содержит
ли
запись
{
поисковый
текст
.toLowerCase 0
+
(blog[i] •
Ы о , 1 1 Ь .....................*
blog[i] .
"l
" ^
) '■
break;
} } //
if
Если
поисковый
текст
не
найден,
сообщим
об
этом
(i = = containing alert("Sorry,
there
are
no
blog
the
search
text.
),
entries
date searchText
searchtext getMonthQ
далее >
447
реш ение задачи с магнитами
Решение задачи с магнитами Вот как выглядит функция зеагсЬ В Х о д ( ) , отвечающая за циклический просмотр записей блога и поиск в них указанного пользователем текста. В озьм ем т ек ст п о и скового за п р о с а из т е к с т о в о го поля.
function
searchBlogO
searchText
var for
(var
i =
0;
//
Проверяем,
if
(b lo g [i]. a l e r t (" ["
{
blog.length
X <
содержит
body +
ли
запись
i ++)
').value;
{
поисковый
текст
l . t o L o w e r C a s e O .i n d e x O f ( s e a r c h T e x t .t o L o w e r C a s e ())
(blog[i] .
date 1
blog[i].date.getDate0
blog[i] .
searchtext
Г- d o c u m e n t . g e t E l e m e n t B y l d ('
bodi
+
'7-
getMonthO + blog[i].
1
+
jJ "
date
*
getFullYearO
+
"]
I I;
break;
} } //
if
Если
(i = =
поисковый
текст
не
найден,
there
are
no
Если i р а вн о св о й с т в у le n g th о б ъ е к т а Ыод, зн а ч и т , все з а ' писи уж е были п р о с м о т р е н ы и совп адени й не обнаруж ено.
глава 9
об
этом
blog.length
'IWtC'Sorry,
448
сообщим
blog
entries
containing
the
search
text.");
^ о с л е со вп а д а ю щ его т е к с т а оы бодит ся д а т а зап иси в квад р а т н ы х скобках в ф о р м а т е
М М /ДД/ГГГГ,
!=-l)
^
" +
{
оживляем данные
Поиск заработал! И так, г о то в а в е р с и я Y o u C u b e 2.0 с ф у н к ц и ей п ои ска, р аб о таю щ ей б л аго д ар я св о й ствам о б ъ е к т а S t r i n g . В ы в и д и те, каки м о б р азо м о б ъ е к т ы д ел аю т д ан н ы е акти вн ы м и . В д ан н о м случае с т р о к а т е к с т а (о б ы ч н ы е д ан н ы е) п р е в р а т и л а с ь в структуру с п о в ед ен и ем (о н а ум еет осущ ествлять п о и ск). С ам ое гл авн о е, ч т о Руби н е п р и ш л о с ь и зо б р е т а ть с о б с т в е н н ы й п о и с к о в ы й м ех ан и зм , а о св о б о д и вш ееся таки м о б р азо м в р е м я о н а п о т р а т и л а н а в ед ен и е блога. в О 0
18/29/2008] Met yp with some fellow cubers to diseass the prospect of a 7x7x7 cube. Mixed feelings.
Search
Поиск no бло- L ry — это золлечаj тельно!
feelings.
Show ДІІ 8І09 E ^ t r i e s J
............ ..............
Руби в в о с т о р ге о т н о в о й ф у н к ц и о н а л ьн о ст и блога, но о н а н е и з тех, к то п о ч и в а е т н а лаврах. И уже п о дум ы вает о в е р с и и Y o u C u b e 3.0...
далее >
449
на самом деле они вовсе глупые Часагю З ад аваем ы е B o iij= > o c : b i
3 * Неужели каждая строка это дей ствительно объект? ! Да. Все строки в JavaScript являются объектами. Если в коде JavaScript вы по местите свое имя в кавычки, например
«Ruby»,
вы создадите объект. Такой под ход может казаться излишеством, но его
преимущество в том, что каждая строка умеет делать много полезного, напри мер: она знает свою длину, умеет искать заданные последовательности символов и многое другое.
3 * Но строка так похожа на массив, даже все ее символы имеют свои индексы. Неужели она — массив? Q ; Нет. Строка определенно не являет ся массивом. Однако и в самом деле мно гие методы объекта S t r i n g производят операции над данными таким образом, как будто перед нами массив, состав ленный из набора символов. Например, первый символ строки имеет индекс О, и этот индекс инкрементно увеличивается. Но доступ к любому элементу массива можно получить, указав его индекс в ква дратных скобках ( [ ]). Со строками такое невозможно. Считайте для простоты, что вы работаете с массивом символов, учитывайте разницу между работой с объ ектами
S trin g
Можно ли в функции поиска
s e a r c h B l o g () использовать метод c h a r A t () вместо i n d e x O f () ? Q ; Нет. 1\Летод
charA t ()
ищет еди
ничные символы, в то время как в блоге обычно хотят найти слово или даже фразу. 1/1менно поэтому для данной цели больше подходит метод i n d e x O f о , умеющий искать произвольные наборы символов.
Можно ли найти все вхождения поискового запроса в текст блога?
Зачем в функции
s e a r c h B l o g () два раза вызывает ся метод to L o w e r C a s e () ? Q ; Ответ на этот вопрос связан с про блемой регистра при поиске по блогу. Ведь если пользователь ищет, например, слово «cube», его, скорее всего, интере суют все варианты этого слова: «cube», «Cube», «CUBE» и т. д. Проще всего эту проблему можно решить преобразова нием как текста блога, так и поискового запроса к одному регистру. Хотя в нашей
s e a r c h B l o g О использу t o L o w e r C a s e ( ) , можно было взять и метод t o U p p e r C a s e ().
функции
ется метод ! Да. 1\/1етод i n d e x O f () по умол чанию ищет только первое вхождение. Но ему можно передать еще один необя зательный аргумент, указывающий, где следует начать поиск. Предположим, вы ищете слово «cube» и обнаружили его под индексом 11. Снова вызвав метод
Главное, выполнить поиск без учета регистра букв.
in d ex O f
() со вторым аргументом 11, вы инициируете новый поиск, начинаю щийся с индекса 12. Таким образом, для продолжения поиска вам нужно только передать индекс найденной строки методу
i n d e x O f {).
и A rr a y .
КЛЮ ЧЕВЫЕ МОМЕНТЫ
■
Метод t o S t r i n g () обеспечивает текстовое пред ставление объектов.
Метод s o r t {) объекта A r r a y сортирует массив в нужном вам порядке.
■
Как массивы, так и строки являются объектами и получают способ хранения данных и методы от стандартных объектов A r r a y и s t r i n g .
Метод i n d e x O f () объекта s t r i n g ищет строку текста в другой строке, возвращая индекс обнару женного совпадающего текста.
450
глава 9
оживляем данны е
Случайный Выбор в б еск о н е ч н о м с т р ем л е н и и п о д д ер ж ать и н т е р е с п о л ь зо в ат ел е й к своем у блогу Руби р е ш и л а д о б а в и т ь к нем у ф ункц ию , к о т о р а я , как ей к аж ется, д о л ж н а п о н р а в и т ь с я п о с е ти те л я м . Э то кн о п к а R a n d o m , п о зв о л я ю щ ая в ы в е с ти случайную запи сь. ooObe,‘jo tth e . і^ с и Ь е - І
__ ____ —
ordered,.
p , o ip e c t o f o .7 > .7 ,o 7 cube,.
c u b e ^ b u t o f co u n e ,. noM> I ’m,
cyv\£'
^ » ^р іг Щ 'ІО г с и п е м ! or\e,.
Возможность выбора слу чайной записи сделает блог УоиСиЬе еще более забавным и загадочным.
Руби — ф а н а т к а го л о во лом ок и т а и нст вен на я женщина.
Ш ТУРМ Как вы реализовали бы случайный выбор записи из блога?
далее ►
451
есе на своем мест е
Объект Math Ч т о б ы д о б а в и т ь к блогу Y o u C u b e в о зм о ж н о с ть п ер е х о д а к случай н ой зап и си , нам п о тр еб у ется сп о со б г е н е р а ц и и сл учай н ы х ч и сел . В это м нам п о м о ж ет в с т р о е н н ы й о б ъ е к т Jav aS crip t, к о т о р ы й н е я в л я е т с я н асто л ь ко «ж ивы м », как о с тал ь н ы е зн ак о м ы е вам о б ъ екты . Э то ст ан д ар т н ы й о б ъ е к т Math, в н у тр и к о т о р о г о г е н е р я т с я случай н ы е чи сл а. П р и это м он н е м е н я е т н и к а к и х д ан н ы х и н е и м е е т возд ействую щ их н а в н у тр ен н и е д ан н ы е м ето д о в. О к р у г л я е т число с п л а —баю щ ей т очкой до целого. В о звр а щ а ет целое о к р у гл е н и е м числа в м еньилую с т о рону.
Возвраицает целое .о к р у гл е н и е м числа в Ьбльш ую ст орону.
М а т е м а т и ч ес к а я к о н с т а н т а , 3 ,1 4 .
Г е н ер и р у е т случайное число о т о до 1 .
О б ъ е к т M ath я в л я е т с я н а б о р о м м а те м а т и ч е ск и х м етод ов и к о н стан т. У н его н е т п е р е м е н н ы х , с о о т в ет с т в е н н о , о н н е и м еет со с то я н и я — вы н е м о ж ете и с п о л ь зо в ат ь его д ля х р а н е н и я и н ф о р м а ц и и . Е д и н ств ен н ы м и д ан н ы м и эт о го о б ъ е к т а яв л я ю т ся н еск о л ьк о к о н с та н т, в т о м ч и сл е P I (3 ,1 4 ). Н о о н об лад ает весьм а п о л е зн ы м и м етодам и. О д и н и з н и х , м етод ra n d o m (), со зд ае т ч и с л а с д е с я т и ч н о й т о ч к о й в п р о м еж утк е о т О до 1.
ажншб
Напишите результаты вызова методов объекта
Объект Math состоит из набора математических методов и констант.
Math.
Ma±h.round(Math.PI) Math.ceiling(Math.PI)
.......
Math.random()
....... Q u iB e i» н а Cinj=>. 4 5 4 -
452
глава 9
оживляем данные
а в ъ Ш ^
. 'т
- Ы
А 'Ш
-
Ö СЁБЁ
Интервью недели: К о гд а м а т е м а т и ч е с к и е ф у н к ц и и с т а л к и в а ю т с я
Head First: Я совсем запутался. Вы о б ъ ект, но с о д е р ж и т е в себе всего л и ш ь н а б о р м атем ати ч ес к и х м ето д о в и н еск о л ьк о ко н стан т. Я ж е думал, ч то о б ъ е к т ы д о лж н ы д ел ать дан н ы е а кти в н ы м и . Т о есть б р а т ь д ан н ы е и п р и п о м ощ и м ето д о в д ел ать с н и м и в ся ки е удиви т е л ь н ы е вещ и. Math: Д а, т а к т р а д и ц и о н н о п р и н я т о думать, н о н е все о б ъ е к т ы п р е д н а зн а ч е н ы д ля э т о й ц ел и . Н е к о т о р ы е и з н и х могут и гр а т ь р о л ь о р г а н и за т о р о в , как я, н а п р и м е р .
Head First: Н о р азв е все эт и м атем ати ч еск и е м ето д ы н ел ь зя со зд ать в ви д е с тан д ар тн ы х ф ункций? IVIath: Р азум еется, м о ж н о , н о вы заб ы в аете, ч т о я зы к Jav aS crip t п о с т р о е н и з о б ъ екто в. Т а к ч т о по сути т а к о й вещ и , как « стан дарт ная» ф у н кц и я, н е сущ ествует. Head First: Н о я создавал ф у н кц и и вн е о б ъ ек то в , и о н и п р е к р а сн о р аб о тал и . IVIath: Н а сам ом дел е все ф у н кц и и яв л яю тся м етод ам и, т а к как о н и п р и н а д л е ж ат какомул и б о объекту, и н о гд а скры том у. Head First: З н а ч и т , в о т почем у вы с о д ер ж и те э т и м а те м а ти ч е ск и е м етоды ...
IVIath: И н е дум айте, ч то отсу тстви е д ан н ы х, к о т о р ы м и я могу уп р авл ять, и ск л ю ч ает м ен я и з со сл о в и я о б ъ екто в.
Head First: Ч т о вы и м е е т е в виду? Math: Ну, п р ед став ьте л ю д ей с о б щ и м и и н т е р есам и . Ч а с то о н и о б ъ е д и н я ю тс я в группы по и н тер есам . М а тем ати ч еск и е м ето д ы , к о н еч н о , н е т а к со ц и ал ьн о а к ти в н ы , как лю ди, но и о н и и м ею т вы году о т о р г а н и за ц и и , к о т о рую я им п р ед о ставл яю .
Head First: Вы х о т и т е сказать, ч т о у н и х м н о го общ его?
Math: Да! Все о н и р еш аю т м ате м ати ч е ск и е зад ач и , н а п р и м е р округл яя ч и сл а, в ы п о л н я я т р и г о н о м е т р и ч е с к и е о п е р а ц и и и ген ер и р у я случай н ы е числа. Head First: В ы упом янули г е н е р а т о р случай н ы х ч и сел . Я слы ш ал, ч т о н а сам ом дел е он и н е случайны . Э то правда? Math: Д о л ж е н п р и зн ат ь с я , ч то да. О н и д ей с т в и т ел ь н о н е совсем случайн ы , как и б оль ш и н ство случайн ы х ч и сел , ген ер и р у ем ы х ком п ью тер о м . О н и «псевдослучайны », н о для б о л ьш и н ства задач эт о го д о стато ч н о . Head First: П севд осл уч ай н ость — эт о как псевдонаука... и л и псевдокод? Math: И да, и нет. Н е т , н и ч его п о д о б н о го псевдонауке. И да, п о х о ж и н а п севд окод , ведь он п р е д н а зн а ч е н д ля п о к аза о с н о в н о й и д еи кода, н е я в л я я с ь им п о сути. Т ак и псевдослу ч ай н ы е ч и с л а и м и ти р у ю т хаос, н е будучи по сво ей п р и р о д е случайны м и. Head First: Т о есть и х м ож н о с ч и тат ь до ста т о ч н о случайн ы м и для б о л ьш и н ств а п р и л о ж е н и й JavaScript? Math: Д а. И эт о х о р о ш ее в ы р аж ен и е: «доста т о ч н о случайны е». В ряд л и с т о и т и сп о л ьзо вать и х для задач, св я за н н ы х с н ац и о н а л ь н о й б езо п асн о стью , н о д ля о б ы ч н ы х сц ен ар и ев о н и в п о л н е подходят. Head First: П о н я т н о . С п аси бо за вашу о т к р о в е н н о с т ь п о поводу сл учайн ы х чисел. Math: Рад бы л побеседовать... как вы зн аете, я н е умею врать.
далее *■
453
реш ение упражнения
Вот результат вызова методов объекта Math. З Д 4 о кр угл е н о до 3.
решение
5 Л 4 окр углено ooepXj до 4.
Math.round(Math.PI)
3
Math.ceiling(Math.PI)
4 ^ 7 7 3 7 ----------------
Math.random()
?
/K
П р о с т и т е , но э т о был во пр о с с п о дв о хо м ! О т в е т о м на него являет ся сл учайное число.
к о н с т а н т а Р1
значение
Генерация случайных чисел Все числа Не важно, псевдослучайные или нет числа генерируются методом в диапазоне rando m () объекта Math, они полезны в нашем случае, когда нужно за о т о до 1 . ставить приложение YouCube сделать случайный выбор из набора дан ных. Проблема в том, что метод ran dom () возвращает число в диапазо не от Одо 1, в то время как Руби требуется число от Одо конца массива записей. Другими словами, нам нужно создать случайный индекс. 0.?8990286m85206
f -'o k --З
a l e r t ( M a t h .r a n d o m ());
0-436133S831S1724 a l e r t ( M a t h .r a n d o m ()); ■ a l e r t ( M a t h .r a n d o m { ) ) ; •
0.962859892?91690S
Для получения случайного числа в диапазоне, отличном от О до 1, вам потребуется еще один метод объекта Math. Метод f l o o r () округляет число до ближайшего целого, отбрасывая дробную часть. Именно он наилучшим образом подходит для наших целей.
f '- ; о к ^ З
0 - 5
Г
Ф
var
V
ttt f
454
глава 9
oneToSix
= Math.floor(Math.random(
1-6
6)
1;
оживляем данные
Часзцо
чаДаБаеМые БоЦ РоС Ь!
Почему не требуется создавать объект Math? Q ; Этот вопрос касается крайне важного понятия, связанного с объектами. Так как объекг
M ath
В чем разница между методами и f l o o r О объекта
ro u n d О Math?
не содержит данных,
которые может изменять, его не требуется создавать. Как вы помните, этот объект представляет собой всего лишь набор статических методов и констант, так что все его составные части уже существуют — и вам просто нечего создавать. Впрочем, все это станет понятнее в главе 10, когда мы приступим к изучению классов и реализаций объектов.
Что еще умеет объект Math? Q ; Многое. Например, два полезных метода, которые нам пока не
Q ; Метод r o u n d ( ) округляет в зависимости от значения десятичной части. Например,
требовались — m in () и max (), анализируют два числа и возвращают
M a th , r o u n d (1 1, 37 5)
a b s O возвращает положительное число вне зависимости от переданного
даст
в результате 11, в то время как M a t h . r o u n d (11 , 625) - 12. Метод же f l o o r ( ) всегда округляет путем отбрасывания десятичной части, не важно, насколько она велика.
меньшее или большее из них. Метод
ему аргумента.
реш ение упражнения
Возьми В руку карандаш 'ешение
Вот код функции гапс1отВ1од ( ) , случайным образом вы бирающий запись из блога и отображающий ее в отдельном окне.
И с п о л ь зу й т е сл у'члйн об число для вы бора зап и си .
Г е н е р и р у е т сл уч а й н о е число о ди ап азон е о т о до числа на единицу м е н ь ш е го , чем к о л и ч е ст во за п и сей в блоге.
fu n c tio n ra n d o m B lo g Q { / / В ы б ер и т е случай н ое, число о т О до числа за п и с ей - i v a r i = M a th .flo o r(M a th .r a n d o m () * h log.ien gth);
4 ------ —
----- -
a le r t( “[" 4- (b lo g li].d a te .g e tM o n tk () + i ) + " / " + h lo g [i].d a te .g e tP a te Q + " /“ blogliJ.date.getF u liY earQ +■ "] " + b lo g [i].b o d y); }
О т ф орм ат и руй т е резул ьт а т т аким об р а з о м , чт обы п о сл е т е к с т а зап и си вы во ди лась ее д а т а в виде М М / Д Д / Г Г Г Г .
Хотелось бы чего-нибудь ещ е... Б л о г Руби т е п е р ь п о д д е р ж и в а е т ф ункц ию п о и с к а случайн ы х со о б щ ен и й , и о н а счастл и ва. Т е п е р ь п о л ь зо в а т ел и п р и п р о см о тр е за р а н е е за и н тр и го в а н ы , ведь о н и н е зн аю т, какая из за п и с е й будет им по казан а. ;.Mixed
С лучайны м о б р а зо м оы оранная за п и сь
олога.
feelings ^^ x 7 x 7 c u b e fo r*a le o n lin e ,Y ik « > .T h a t
{8/16/2008) Managed to get a headache tolling over the
|^ S n e w c » b e b u to r c o u m .n o w T m b « «
o 'o S w c u b e lo r ie s d . t f s a ^ a ! pearl, яио» АН goa
456
глава 9
Н е с м о т р я н а в о сх и щ ен и е н о в о й ф ун кц и ей , Р^би н е м о ж е т отд ел аться о т чувства, ч то блогу все ещ е чего-то н е хватает. Ее об ъ ек т B lo g в н а сто я щ е е в р е м я п р е д став л я ет с о б о й всего пару сво й ств, в основу р аб о ты к о т о р ы х п о л о ж ен ы о т д е л ьн ы е ф ункц ии. Н е сам ая лучш ая к о н стр у к ц и я, н а взгляд Руби...
оживляем данные
Объект В поисках geucmBuu Руби обеспокоена. Поведенческая часть объекта совершенно недостаточна и нуждается в серьезной перестройке, в резуль тате которой отдельные задачи начнут решаться при помощи методов. Руби нужны методы, которые определят поведение объекта Blog!
А ведь я могла бы воспользоваться неко торыми методами. — у
------------
Возьми 8 руку карандаш Изучите код YouCube и обведите код, который, с вашей точки зрения, можно поместить в методы объекта Blog; присвойте методам имена.
f u n c t i o n showBlog(numEntries) { / / Сортируем записи в обратном хронологическом порядке (последние впереди) b l o g . s o r t ( f u n c t i o n ( b l o g l , Ыод2) { r e t u r n b l o g 2 . d a t e - b l o g l . d a t e ; }); / / Выбираем число записей, чтобы при необходимости показать блог целиком i f ('n u m E n trie s) num Entries = b l o g . l e n g t h ; / / Показ записей блога v a r 1 = 0 , b logT ext = w h ile ( i < b l o g . l e n g t h && i < num Entries) { / / Используем для каждой записи серый фон i f (i % 2 == 0) b lo g T e x t += "<р s t y l e = ' b a c k g r o u n d - c o l o r : #ЕЕЕЕЕЕ'>"; else b lo g T ex t += "<p>"; / / Генерируем отформатированный HTML-код блога b lo g T ex t += "< stron g> " + ( b l o g [i ] . d a t e . g etM o n th () b lo g [ i] .d a te .g e tD a te 0 + "/" + b lo g [i] . d a t e . g e t F u l lY e a r O + " < / s t r o n g X b r />" b l o g [ i ] . b o d y + "</p>"; i++; / / Располагаем HTML-код блога на странице docum ent. g e tE le m e n tB y ld (" b l o g " ) . innerHTML = b lo g T e x t; }
f u n c t i o n se a rc h B lo g O { v a r s e a rc h T e x t = d o c u m e n t .g e t E l e m e n t B y I d ( " s e a r c h t e x t " ) .v a lu e ; f o r (var 1 = 0 ; i < b l o g . l e n g t h ; i++) { / / Проверяем, включает ли запись строку поиска i f ( b l o g [ i ] . b o d y .t o L o w e r C a s e О .in d e x O f(s e a rc h T e x t.to L o w e rC a s e ( != - 1 ) + ( b l o g [ i ] . d a t e . g e t M o n t h O + 1) + " / " + b l o g [ i ] . d a t e . g e t D a t e 0 + " / " ale rt(" b lo g i ] . d a t e . g e t F u l l Y e a r O + "] " + b l o g [ i ] . b o d y ) ; b re a k ; }
/ / Если строка поиска не обнаружена, сообщаем об этом i f (i == b l o g . l e n g t h ) a l e r t ( " S o r r y , t h e r e a r e no b lo g e n t r i e s c o n t a i n i n g t h e s e a r c h t e x t . " ) ; }
f u n c t i o n randomBlogO { / / Выбираем случайное число от О до b l o g . l e n g t h - 1 v a r i = M ath. f l o o r ( M a t h . random О * b l o g . l e n g t h ) ; a l e r t ( " [ " + ( b l o g [ i ] . d a t e . g e t M o n t h O + 1) + " / " + b l o g [ i ] . d a t e . g e t D a t e () + " / " + b l o g [ i ] . d a t e . g e t F u l l Y e a r O + "] " + b l o g [ i ] . b o d y ) ; }
далее >
457
реш ение упражнения
Возьми в руку карандаш 'ешение
Вот код, который можно поместить в методы объекта B lo g .
f u n c t i o n showBlog(numEntries) { / / Сортируем записи в обратном хронологическом порядке (последние впереди) Ы о д . s o r t ( f u n c t i o n ( b l o g l , blog2) { r e t u r n b l o g 2 . d a t e - b l o g l . d a t e ; }); / / Выбираем число записей, чтобы при необходимости показать блог целиком ii ff f( !I num r m m F .n 1 - г -i ^ . Entries) num Entries = b l o g . l e n g t h ; М е т о д B log.toH TM LO п р е о б р а з у е т за п и с ь блога ^от ф орм ат ированны й
/ / Показ записей блога v a r i = О, b lo g T ex t = w h ile (i < b l o g . l e n g t h && i < num Entries) { / Z--i^5nojib3yeM для каждой записи..серый фон (i % 2 == 0) b lo g T ex t += "<p s ty le = 'b a c k g ro u n d -c o lo r:# E E E E E E '> " ; else b lo g T ex t += "<p>";
n iM L -ф р а г м е н т .
^
/ / Генерируем отформатированный HTML-код блога b lo g T ex t += "<stron g> " + ( b l o g [i ] . d a t e . g etM on th () b lo g [ i] .d a te .g e tD a te 0 + " /" + \ b l o g [ i ] . d a t e . g e t F u l l Y e a r 0 + " < / s t r o n g x b r />" + \ W o g [ i ] . b o d y + "</p>"; i++; }
/ / Располагаем HTML-код блога на странице document.getElementByld("blog").innerHTML
=
blogText;
}
f u n c t i o n sea rc h B lo g O { v a r s e a rc h T e x t = docum ent. g e tE le m e n tB y ld (" s e a r c h t e x t " ) .v a l u e ; f o r (var 1 = 0 ; i < b l o g . l e n g t h ; i++) { / / Пр0 ВЁРяам..---В1ашы.а£-Т .пи запись строку поиска_____________ i f Q b l o g [ i ] . body. toLowerCase () . indexOf ( s e a r c h T e x t . to L o w e r C a 's ^ ^ a l g g e - r - r - -b (bTog [ 11-Т^ЭТГ Г?5ТтапГГТ7~ Т - Т Г ^ - "7 " '''~Г-И:одТТ7^ (_ b l o g [ i ] . d a t e . g e t F u l l Y e a r 0 + "] " + b l o g [i 1 . b o d v ); Ь г е а т г г " ----------------- — —------------------------------------------------ -------------------------- --- —
Г^~ГТЗ
........ .....
}
/ / Если строка поиска не обнаружена, сообщаем об этом i f (1 == b l o g . l e n g t h ) a l e r t ( " S o r r y , t h e r e a r e no b lo g e n t r i e s c o n t a i n i n g th e s e a r c h t e x t . " )
}
f u n c t i o n randomBlogO { / / Выбираем случайное число от О до b l o g . l e n g t h - 1 v a r i = M a th .flo o r(M a th .ra n d o m О * b l o g . l e n g t h ) ; a l e r t (" [" + ( b l o g [i ] . d a t e . g etM o n th () + 1) + " / " + b l o g [ i ] . d a t e . g e t D a t e () + " / " + b l o g [ i ] . d a t e . g e t F u l l Y e a r 0 + "] b lo g [i].b o d y );
}
M em дбльилую н а гр у зк и Должен о т о б р а ж а т ь х орош о
о т ф о р м а т и р о в а н н ы й блог.
458
глава 9
Н ебольш ой по р а з м е р у , но п олезны й м е т о д Blog■ContalnsTextQ б у д е т о т в е ч а т ь за п ои ск т е к с т а в блоге.
б ст року^ Е го и м е е т см ы сл и с п о л ь з о в а т ь в си т у а ц и ях, к о гда д а т а в к в а д р а т ных скобках вы води т ся п о сле т е к с т а записи.
Часзцо
оживляем данные
^аД аБ аеМ ы е B o n j> o c ; b i
Как понять, какой код можно превратить в метод? 0 ; Для начала следует понять, для чего будет предназначен этот метод и какие действия он будет совершать над данными объекта. В некоторой степени определение методов объекта зависит от того, что именно делает или должен будет делать объект. После чего мы даем объекту возможность выполнять эти действия.
Например, объекту B lo g целесообразно иметь способность превращать себя в строку или в отформатированный HTMLкод, ведь эти действия требуют доступа к внутренним данным блога. Аналогично, поиск текста в записях — это внутреннее действие объекта B lo g , а значит, имеет смысл превратить его в метод.
I
За пределы возможностей объекта
B lo g выходят такие действия, как поиск или отображение списка записей. Ведь этот объект представляет единственную запись. Именно поэтому массив Ы о д состоит из набора отдельных объектов B lo g . И каждый такой объект никак не должен касаться действий, производимых со всем набором.
3 * А как насчет примера действия, которое объект B lo g не сможет выполнить?
Превращение функции В метод Т еп ер ь , когда м ы р еш и л и , к ак и е и м е н н о ф р а гм е н т ы кода блога Y o u C u b e д о ст о й н ы превраш ;ения в м ето д ы о б ъ ек т а B lo g , п о см о тр и м н а саму проц едуру п р е о б р а зо в а н и я . В ка ч е с тв е п р и м е р а возьм ем м е тод c o n t a i n s T e x t ( ) , о тв е ч а ю щ и й за п о и с к в т ел е зап и си указан н ого п о л ь зо в ател ем н а б о р а сим волов. П е р е м е щ е н и е ко д а в м етод п р о в о д и т о п е р а ц и ю н е п о ср е д с тв е н н о над сво й ств о м b o d y о б ъ е к т а B lo g , в о т л и ч и е о т л о к а л ь н о й п е р е м е н н о й в ф у н кц и и s e a r c h B lo g ( ) . В от ^ Ц О Г п о ш аго в о е о п и с ан и е про ц есса: О б ъ яв и м м етод, со стави м сп и со к аргум ентов, н а п р и м е р , для м ето д а c o n t a i n s T e x t () эт о с т р о к а пои ска.
О О
П о м ести м код в н о в ы й м етод. З астав и м код и с п о л ьзо в ат ь с в о й ств а о б ъ екта, в наш ем случае св о й с тв о t h i s . b o d y .
to S tr in g О ^
І І И up w ith eoifcWP*® fe llo w c u b e rs p to d iscu ss th e і tcHT-MLO X —, p r o s p e c t..."
I
d a te
lA u g u st 1 4 th ,
--------— —
é
c o n t a in s T e x t( ) ««ИМ Я
з
Возьми в руку карандаш Напишите код для метода c o n t a i n s T e x t ( ) , создавае мого в конструкторе B lo g () путем назначения литерала функции ссылке t h i s . c o n t a in s T e x t .
далее ►
459
бы ст ры е изменения
Возьми в руку карандаш Решение
Вот код для метода c o n t a i n s T e x t ( ) , создаваемого в конструкторе B l o g () путем назначения литерала функции ссылке t h i s . c o n t a i n s T e x t .
М ето Э с о зд м ш с я
назначением л и т е раАй ф ункц и и ссы лки на него. .7. f . ’^ n c t i p n { t e x t ) {
r e t u r n (tkis.bodij.toL ow erC aseQ .m dexO f(teK t.toLow erC aseQ ) != - 1 );
V и с п о л ь зу е т с я для со зд а \ _ т я м ет о д а т е м же способом , к о т о р ы м с его п о м о щ ь ю создавались сво й ст ва
м ет о д а и м е е т непосредст венны й к сво й ст ва м о б ъ ект а пр и п о м ощ и клю чевого слова this.
Восхитительный новый объект blog
Эй,теперь я в хорошей форме!
Еще два метода соединились с методом c o n t a i n s T e x t () в новой версии объекта B lo g , который теперь обладает и свойствами и по ведением. f u n c t i o n B l o g (body, d a t e ) // н а з н а ч а е м с в о й с т в а
~ СоъЪание и и н и ц и а л и за ция свойст в.
{
t h i s . body = body; t h i s . date = date;
М ет о д to S trin g Q в о з вр а щ а е т за п и сь блога
of
the b l o g
+ 1)
Г ° оиде т ек с т о во й W ст р о ки .
entry
+ "/"
t h i s .d a t e .g e t D a t e
this.body;
};
// Возвращаем форматированное HTML-представление th is .to H T M L = f u n c t i o n ( h i g h l i g h t ) { // И с п о л ь з у е м д л я в ы д е л е н и я с е р ы й ф о н ?
"<Р
записи
М ет од toH TM L() в о з в р а щ а е т за п и сь блога как о т ф о р м а т и р о ванный Н ТМ и-код.
s ty le - b a c k g r o u n d - c o lo r T # E E E E E E '> "
" <р>";
// Г е н е р и р у е м о т ф о р м а т и р о в а н н ы й H T M L к о д б л о г а Ы о д Н Т М Ь + = " < s t r o n g > " + ( t h i s .d a t e . g e t M o n t h () + 1) + " / " + ' r t h i s ’d a t e . g e t F u l l Y e a r O + " < / s t r o n g X b r this.date.getDateО + t h i s . b o d y + "</p>"; return blogHTML; -
};
460
глава 9
/>"
М ет о д containsT extQ во звр , а щ а ет значение tr u e , если т е к с т с о д ер ж ит п о и ско вую ст р о ку.
// П р о в е р я е м , с о д е р ж и т л и б л о г с т р о к у т е к с т а t h i s containsText = f u n c t i o n ( t e x t ) { r e t u r n ( ( t h i s . b o d y . t o L o w e r C a s e 0 . i n d e x O f ( t e x t .t o L o w e r C a s e
};
<
J
‘^ ' ^ ф о р м а т и р о в а н н у ю '
// R e t u r n a s t r i n g r e p r e s e n t a t i o n t h i s . toString = f u n c t i o n 0 { r e t u r n "[" + ( t h i s . d a t e . g e t M o n t h t h i s . d a t e . g e t F u l l Y e a r O + "]
b lo g H T M f™ \lg h lig h t
^
0 ) != -1);
оживляем данные
Ч то дают объекты блогу YouCube? Думаю, вы поняли преимущества объектно-ориентированного програм мирования еще до появления новой версии объекта B log (она доступна по адресу http://www.headfirstlabs.com/boohs/hjjs/). Теперь, когда решение ряда важных задач отдано на откуп методам объекта B log, код сценария стал намного проще.
Новый объект Blog упрощает сценарий блога YouCube.
/ / Show t h e l i s t o f b lo g e n t r i e s f u n c t i o n showBlog(numEntries) { / / Сортируем записи в обратном хронологическом порядке (последние впереди) Ы о д . s o r t ( f u n c t io n ( b l o g l , Ыод2) { r e t u r n b l o g 2 . d a t e - b l o g l . d a t e ; ) ) ; / / Выбираем число записей, чтобы при необходимости показать блог целиком i f ( [n u m E n tries) num Entries = Ы о д . l e n g t h ; / / Цикл пока записей блога v a r 1 = 0 , blogListHTML = w h ile (i < b l o g . l e n g t h && i < num Entries) { blogListHTML += Ы о д [i] . toHTML ( i % 2 == 0) ; i+-i-; }
М ето Э toHTMLQ sAOAHOcmbH) о т ве ч а е т за HTM Lih op м а т и р о ва н и е записей блога.
/ / Располагаем HTML-код блога на странице d ocum ent.getE lem entB yld("blog").innerH T M L = blogListHTML; }
Ищем фрагмент тек ста в записях блога f u n c t i o n sea rc h B lo g O { v a r s e a rc h T e x t = d o c u m e n t .g e t E l e m e n t B y I d ( " s e a r c h t e x t " ) .v a lu e ; f o r (var 1 = 0 ; i < b l o g . l e n g t h ; i++) { М ет о д containsT extQ / / Проверяем, включает ли запись строку поиска и щ е т 6 записи у к а за н н у ю i f (b lo g [i].co n ta in sT ex t(sea rch T ex t)) { п о л ь зо в а т е л е м ст р о ку. a l e r t ( b l o g l i ] ); М ет од to S trin g O break; а вт о м а т и ч е с к и в ы
II
зы вает ся в случаях^ когда за пись и с п о л ь зу е т с я т а м , где нужнй ст рока.
}
/ / Если строка поиска не обнаружена, сообщаем об этом i f ( i == b l o g . l e n g t h ) a l e r t ( " S o r r y , t h e r e a r e no b lo g e n t r i e s c o n t a i n i n g t h e s e a r c h t e x t . " ) ; }
/ / Отображаем случайно выбранную запись f u n c t i o n randomBlogO { / / Выбираем случайное число от О до Ы о д . l e n g t h - 1 v a r i = M a th .flo o r(M a th .ra n d o m О * b l o g . l e n g t h ) ; a l e r t ( b l o g t i ] ); }
~
~
--------- — ------------------ -
далее >
461
гот овност ь к большим делам
YouCube 3 .0 ! Руби о ф и ц и а л ь н о о б ъ яв и л а, ч то о н а д о в о л ь н а в е р с и е й блога Y o u C u b e 3.0 и п р е д п о ч и т а е т вер н у ться к го л оволом к ам и к п о д го то в ке в е ч е р и н к и для т а к и х ж е, как она, ф ан ато в... За п и си блога p m c o p m u p o t o « хо р о ш о о т ф о р м а т и р о в а н н ь ...
...возмож ен поиск по блогу...
г
й
YouCube - Tht
100
Blog for Cube Piwzlers
СрягсН the ffloa i|7x7x7
feelings.
18/29/20081 Met up with some fellow cubers to discuss the prospect o f a 7x7x7 cube. Mixed feelings.
..возмож ен п р о с м о т р случайно вы дранной ізаписи... ^
^
lo lS e new OTbebut of M ^ t o g e t a h c a d a c h e t o f f in g o v e it f iiW »
шЪе 1ofdcied. It's a гей pearl. Show A jij£ i£ ! ! l! £ L j
Blog
462
глава 9
-б л а го д а р я с п е ц и а ль н о м у о З ь е к т у Blogl
оживляем данные
Вкладка Согните страницу по вертикали, чтобы совместить два мозга и реш ить задачу. ^
Что моїуг сделать с данными объекты JavaScript? 'V М хороШо, а ДВа лучше!
Ищите, что хотите, но вряд ли вы найдете что-то лучше, чем о^ к ты Дауа8спр1 для сортировки и анажза данных. Они умеют даже генерить случайные числа.
^ п е Ц и а Л ь Н ы е
о ^ ь е К ш ы
%
Работа со специальными Ф объектами
Если бы все было так легко, мы бы, конечно, так и сделали. иауа8спр1 не гарантирует возврат денег, но вы действительно можете делать с ним все, что захотите. Специальные объекты — это эквивалент тройного эспрессо с сахаром и корицей. Вот такая специальная чашка кофе! Точно так же в специальных объектах вы можете смешивать код, добиваясь именно того результата, который вам нужен, и пользуясь преимуществами свойств и методов. 1/1 в конце получается объектно-ориентированный код, расширяю щий язык иауаЗспр1... только для вас!
мет оды блога
Снова о методах блога YouCube
Блог YouCube работает, но его нельзя причислить к самым удачным образцам о^ектно-ориентированного программирования.
Н е с м о т р я н а т о ч т о в п р о ш л о й главе Руби п р о д ел а л а больш ую раб о ту п о со зд ан и ю о б ъ е к т а B lo g д ля у п р ав л ен и я своим блогом Y ou C u b e, н еск о л ьк о к л ю чевы х для о б ъ е к т н о -о р и е н т и р о в а н н о го п р о гр а м м и р о в а н и я в о зм о ж н о с те й о с тал и сь за кадром . О н а н е удели ла д о л ж н о го в н и м ан и я э ф ф е к т и в н о с т и о б ъ е к т а B lo g , его структуре и, сл ед о ватель н о , в о зм о ж н о с ти р е д а к ти р о в а ть его в будуш;ем.
О с т ан о в и л и с ь м ы , как вы п о м н и те, н а с о зд ан и и т р е х м етод ов для в ы п о л н е н и я св я за н н ы х с блогом задач. ' Последняя версия данных ф а й л о в д о ст уп н а для скачивания по Блог адресу h ttp ://w w w .k e a d fir s t!a b s . с о т / b o o k s/h fjs/. Три метода объекта Blog предназначены для задач, выполняемых внутри за писей блога.
Blog (body, date) ,назначаем свойства .body - body; ite - date;
Мне так нравятся методы объекта Blog.
(
'звратаем строковое представление записи блога :l.toString = functionO
+ 1) + ”/" + this.date.getDateО
{
+ ”/" +
r^i-urn -■[" + (this.date.getMonthO + 1) + / thS.dlte.getEullYearO . " 1 ■■ ^ this.body;
}; // возвращаем форматированное HTML-представление записи t h i s.toHTML - function(highlight)
//
И спол ьзуе м
b S g ^ i "
(
для вьшеления серый фон
i^bligbt , "<Р style=.bac.g.ound-colot:«EEEEE.>.. :
// генерируем отформатированный HTML-код блога ^ ’^ " t r r t : . ; : r t : r V ^ V " " ' t h t r d r t e . g e t P u l l y e a t O
^ t ..</.ttongXb. />" .
this.body + ■'</?>"; return blogHTML;
}; // проверяем, содержит ли блог отроку текста
Н а п е р в ы й взгляд м его д ы , и сп ользуем ы е в блоге Y o u C u b e, вы гл яд ят п р е к р а сн о , н о ес ть од н а проб лем а...
466
глава 10
специальны е объекты
Перегрузка методоВ Т о ч н о т а к ж е, как и сво й ства, м ето д ы о б ъ е к т а B lo g созд ан ы вн утр и к о н с тр у к то р а п р и п о м о щ и кл ю ч ев о го сл о в а t h i s . П р и таком п од ходе д ля каж дого в н о в ь со зд ан н о го о б ъ ек т а B lo g созд аю тся и т р и к о п и и м ето д о в. Т ак ч то , н а п р и м е р , для блога и з ш ести за п и с ей м ы получим ш есть и х ко п и й .
Texto
!^лждый из созданны х о б ъ е к т о в Blog получает contalnsTextO
собст вен ную Копию т р е х методов.
О бъект B log ненам еренно создает больш е м етодов, чем это необходим о, что крайне н еэф ф ек тивн о. Н икуда о т это го н е д еться, ко н стр у к то р B lo g () со зд ает п о т р и м етод а п р и каж дом с о зд ан и и н о в о го о б ъ ек та, и в р езу л ьтате каж ды й о б ъ е к т B l o g п о лучает собственн ую к о п и ю каж до го и з м етодов. Н о есл и св о й ст в а каж дого о б ъ е к т а с о х р а н я ю т у н и кал ьн ы е д ан н ы е , м ето д ы в п о л н е м о ж н о о тд ать о б ъ ектам в со в м е с тн о е п о л ьзо в ан и е. Н аск о л ьк о э ф ф е к т и в н е й б ы ло бы , если бы все о б ъ е к т ы B l o g и с п о л ьзо в ал и одну и ту ж е к о п и ю каж дого и з м етодов. Э то п р е д о т в р а т и л о бы и зл и ш н ее у в е л и ч ен и е о б ъ ем а с ц е н а р и я из-за п о я в л е н и я и зб ы т о ч н ы х м ето д о в по м е р е н е и зб е ж н о го р о с т а ч и сл а зап и сей .
м озговой Ш Т У РМ Что нужно сделать с объектом B log , чтобы код методов не дублировался при создании каждой следующей копии?
далее >
467
а теперь класс... в этой реализации
Классы и реализации П р о б л е м а с д у б л и р о ван и ем м ето д о в за т р а ги в а е т к р а й н е важ ную к о н ц еп ц и ю , связанную с о б ъ ектам и : р азн и ц у между классом и реализацией об ъекта. К л ассо м н а зы в ае т ся о п и са н и е о б ъ екта, ш аб лон , д аю щ и й п р е д с та в л е н и е о том , и з ч его со с то и т о б ъект. Р е а л и за ц и я ж е это сам о б ъ ект, со зд ан н ы й и з класса. В т е р м и н а х р е а л ь н о го м и р а м о ж н о сказать, ч то класс — это п р о е к т дом а, в т о в р ем я как р е а л и за ц и я — сам дом. В зяв за о сн ову о д и н ч е р т е ж , м о ж н о п о с т р о и т ь м ного дом ов.
Класс объекта
Блог
468
глава 10
Реализации объекта
специальны е объекты
Класс объекта — ^ шаблон, в то время как реализация — созданный по этому шаблон^^ объект.
Реализации Класс описывает свойства и методы объекта, в то время как реализация присваивает свойствам реальные данные и за ставляет их действовать. Все реализации имеют собственные копии свойств, что позволяет им уникальным образом отли чаться друг от друга.
body/ "Managed to get a date'' August 16th, 2008 Значения сво й ст в за ча ст ую р а зл и ч а ю т с я у разны х реализаций, п о э т о м у т а к важно, чт обы каждая р е а лиза ц и я обладала собст вен
toString toHTML containsText
ной копией.
Свойства.
(
Л "Found а 7x7x7 cube.
toString М ет оды .
-—
body^
date
X ^ J ^ s t 21st, 2008 /FunctionO functionO
'
У
{ ... { ... }
.^functi^iTo^^
..—
—
.
body "Met up with some..." A в о т дуб ли р о ва т ь м ет о д ы для каждой р еа ли за ц и и вовсе не т ребует ся
date .
toString toHTML
August 29th, 2008
f functionO
{
- N
function() { ... }
containsText V functionO
{
- J
далее >
469
два раза отмерь, один отрежь
Ключевое слово this Д о си х п о р м ы и м е л и дел о в о сн о в н о м со свойствами реализаций. П р и это м каж дая р е а л и за ц и я об лад ала их с о б ст в е н н о й к о п и ей . Т а к и е с в о й ств а л егко и д е н т и ф и ц и р о в а т ь , т а к как и м ен н о о н и за д аю тся в к о н стр у к то р е п р и п о м о щ и к л ю чевого сл о ва t h i s .
f u n c t i o n B log(body, d a te )
Ключевое слово this задает свойства и ме тоды реализаций.
{
t h i s . b od y = body; t h i s . d a te = date ; Э т о свойства реализации, т ак как на них ссы л а ю т -
-------- --------
СЯ
при помощ и ключевого
слова this.
Сущ ествую т и м ето д ы р е а л и за ц и й , н о с н и м и все го р азд о сл о ж н ее, та к как о н и м огут н ах о д и ться в с о б с т в е н н о ст и как р е ал и за ц и и , так и класса. Д о эт о го м о м ен та м ы и м ел и д ел о с м етод ам и , зад ан н ы м и п р и по м о щ и к л ю чево го сло ва t h i s , т о е с ть с м етод ам и р е ал и за ц и й . И м е н н о п оэтом у м ето д ы д у бл и р о вал и сь о т эк зе м п л я р а к экзем пляру.
f u n c t i o n B log(body, d a te )
t h i s . toString = f u n c t i o n O
Все эт о мет оды
{
реализаций, т ак как они задаю т ся
В се реализации обь ект а Blog получаю т собственные копии эт и х методов-
о кон ст р укт ор е
клю чевым словом
this.
th is .to H T M L = f u n c t i o n O
{
t h i s . containsText = f u n c t i o n O
{
Х о р о ш ей н о во стью я в л я е т с я т о , ч т о сп е ц и а л ь н ы е о б ъ ек ты в о все н е о б я зан ы впустую со зд авать дублирую щ ийся код м етод ов с п о я в л е н и ем каж дой н о в о й р е а л и за ц и и . Д о с тат о ч н о со зд ать м етод таки м о б р азо м , ч то б ы все р е а л и за ц и и см огли и с п о л ь зо в ат ь одну и ту ж е к о п и ю его кода.
470
глава 10
специальны е объекты
Методы классов Сущ ествует и д ругой вид м ето д о в, п р и н а д л е ж ащ и й со б с т в е н н о классам , ч то о зн а ч а е т в о зм о ж н о сть доступа в с е х р е а л и за ц и и й к ед и н с т в е н н о й ко п и и . Т а к о й подход н ам н о го э ф ф е к т и в н е й т о го , ч то м ы и с п о л ьзо в ал и р ан ьш е.
Э т о т м ет од принадле ж ит классу Blog, п о эт а м и
Данные эт и р еали за ц и и х р а н я т в своих с во й с т в а х . но д о ст уп к «X м е т о д а м о с ущ е ст в ля е т с я через класс Blog-
Е с ли м ето д п р и н а д л е ж и т классу, к нем у и м ею т доступ все р еа л и за ц и и , и по это м у и х со б с тв е н н ы е к о п и и им уже н е т р е бую тся. Т а к о й по д х о д н ам н о го б о л ее э ф ф е к т и в е н , о с о б е н н о есл и уч есть, ско л ьк о л и ш н и х м ето д о в в и т о г е п о я в л я е тся в п р и л о ж е н и я х , п о с т о я н н о создаю щ их н о в ы е р е а л и за ц и и об ъ ектов. В блоге Y o u C u b e т р и м ето д а ( t o S t r i n g ( ) , toHTML () и c o n t a i n s T e x t ( ) ) д у бл и р о вал и сь бы вм есте с каж дой н о в о й запи сью .
Хранение метода в классе позволяет всем реализациям пользоваться одной копией.
Т е п е р ь о стал о сь п о н я т ь , как сд ел ать та к , ч то б ы м ето д стал п р и н ад л еж ать классу... далее ►
471
у каждого объекта е с т ь ...
Прототипы П о я в л е н и е т о го , ч т о м ы н азв а л и классам и, стало возм ож н ы м в Jav aS crip t б лаго д ар я скр ы то м у об ъекту p r o t o t y p e , сущ еству ю щ ем у как св о й с тв о лю б о го о б ъ екта. И м е н н о о н п о зв о л я е т за д ав ать с в о й ств а и м етод ы , принадлежащие классам. Д ав ай те п о см о тр и м , как эт о д ел ается. яв ля е т с я л и т е р а л .
B l o g .p r o t o t y p e . toHTML = f u n c t i o n O
{
Л
И м я класса.
О б ъ е к т p r o to ty p e д о ст уп ен как с во й ст во класса.
В д ан н о м п р и м е р е м ето д toHTML () д о б а в л я е тся к классу B lo g , а н е к какой-либо р е а л и за ц и и это го класса. Н е в а ж н о , сколько о б ъ е к т о в B lo g м ы создадим , к о п и я м ето д а toHTML () все р ав н о будет то л ь к о одна. Т ак как м ето д toHTML () п р и н а д л е ж и т классу B lo g , в это м ж е классе р а с п о л о ж е н и код, запускаем ы й п р и вы зо ве м етода. Н о т е х н и ч е с к и эт о все р а в н о м ето д р е а л и за ц и и , т ак как он м ож ет б ы ть вы зван н а у р о в н е о б ъ е к т а и и м е е т доступ к свой ствам эт о го о бъ екта.
v a r b l o g E n t r y l = new B log("N ot much go ing o n ." , b l o g E n t r y l . toHTML () ;
К од, за п уска ем ы й пр и вызове м ет о д а toH TM LQ , р а б о т а е т в н у т р и класса.
П р и со зд ан и и следую щ его о б ъ е к та B lo g и в ы зо в е для н его м етод а
toHTML () запускается т о т ж е сам ы й код в н у три класса. В ид ите, как вы го д н о , —с о х р а н и л о д и н р а з, а исп ользуеш ь, скол ьк о нужно!
v a r b lo g E n try 2 = new B l o g ( " S t i l l j u s t hanging a r o u n d ." . b l o g E n t r y 2 . toHTML {)
472
глава 10
О ст а льн ы е объект ы использую т т о т же сам ы й м е т о д класса.
Блог
специальны е объекты
Классы, прототипы и YouCube Руби н ем н о го о ш ел о м л ен а с в ед ен и я м и о классах и п р о т о т и п ах , н о о н а чувствует, ч т о б лог Y o u C u b e м о ж н о вы год н о м о д е р н и зи р о в а т ь , связав м ето д ы о б ъ е к т а B lo g с о б ъ екто м p r o t o t y p e .
Использование объекта prototype для хранения методов блога увеличит эф фективность кода YouCube.
containsTextO
Возьми В руку карандаш Для хранения методов, которые теперь принадлежат классу, в новой версии кода используется объект p r o t o t y p e . Вставь те ваши примечания и объясните, что именно происходит. f u n c t i o n B l o g ( b o d y , d ate) // Н а з н а ч а е м с в о й с т в а t h i s . b o d y = body; t h i s . d a t e = date;
{
} // В о з в р а щ а е м с т р о к о в о е п р е д с т а в л е н и е з а п и с и б л о г а B l o g . p r o t o t y p e .t o S t r i n g = f u n c t i o n O { r e t u r n "[" + ( t h i s .d a t e .g e t M o n t h () + 1) + "/" + t h i s .d a t e .g e t D a t e () + t h i s . d a t e . g e t F u l l Y e a r 0 + "] " + t h i s . b o d y ;
"/"
+
}; // В о з в р а щ а е м о т ф о р м а т и р о в а н н о е H T M L - п р е д с т а в л е н и е з а п и с и б л о г а B l o g . p r o t o t y p e .t o H T M L = f u n c t i o n ( h i g h l i g h t ) { // И с п о л ь з у е м д л я в ы д е л е н и я с е р ы й ф о н var blogHTML = b l o g H T M L + = h i g h l i g h t ? " < p s t y l e = 'b a c k g r o u n d - c o l o r :# E E E E E E '>" // Г е н е р и р у е м о т ф о р м а т и р о в а н н ы й H T M L - к о д б л о г а b l o g H T M L + = " < s t r o n g > " + ( t h i s .d a t e .g e t M o n t h () + 1) + "/" t h i s . d a t e . g e t F u l l Y e a r 0 + " < / s t r o n g X b r />" + t h i s . b o d y return blogHTML;
: " <p>";
+ t h i s .d a t e .g e t D a t e () + + "</p>";
"/"
+
}; // П р о в е р я е м , с о д е р ж и т л и б л о г с т р о к у т е к с т а B l o g . p r o t o t y p e .c o n t a i n s T e x t = f u n c t i o n ( t e x t ) { r e t u r n ( t h i s . b o d y .t o L o w e r C a s e ().i n d e x O f ( t e x t .t o L o w e r C a s e {))
!= -1);
далее *
473
реш ение упражнения
Возьми в руку карандаш 'ешение f u n c t i o n B l o g ( b o d y , d a te) { // Н а з н а ч а е м с в о й с т в а t h i s . b o d y = body; ______ t h i s . d a t e = date;
Итак, для хранения методов, которые теперь принадлежат клас су, в новой версии кода используется объект p r o t o t y p e .
Т еп ер ь в задачу к о н с т р у к т о р а оходит т о ль к о создание и и н и ц иа лизация свойст в.
/ / Возвращаем строковое представление записи блога B lo g .p r o to ty p e .to S tr in g = fu n c tio n O { re tu r n "[" + ^ (th is .d a te .g e tM o n th O + 1) + " /" + t h i s . d a t e . g e tD a te () t h i s . d a t e . f e t F u l l Y e a r 0 + "] " + th is .b o d y^; 1 Т ак ка к м ет о д ы ^на— ■—■ "
~ — ~— ----------— значаю т ся не о 5 ъ -
11 Возвращаем от^^матированное HTML-представление записи блога е к т у В Іод, НОЗНйЧІBlog.prototype.toHTMb = fu n c tio n (h ig h lig h t) { н и е п р о и с х о д и т Ьне / / Используем для выделения серый фон конст рукт ора.
var blogHTML = blogHTML += h ig h lig h t ? "<p sty le = 'b a c k g ro u n d -c o lo r: #EEEEEE'>" : "<p>"; / / Генерируем отформатированный HTML-код блога blogHTML += "<strong>" + ( t h i s . d a t e . getMonth() + 1) + "/" + t h i s . d a t e . g e tD a te () + V" + t h i s . d a t e . g e t F u l l Y e a r О + " < /s tr o n g X b r />" + th is .b o d y + "</p>"; ^ о г о , чт обы во спо льзова т ься клю чевы м словом th is
/ / Проверяем, содержит ли блог строку текста ^ К о н ст р укт о р е BlogQ. B lo g .p ro to ty p e.co n tain sT ex t = fun ctio n (text) { re tu r n ( th is .b o d y . toLowerCase0 . in d e x O f(te x t. toLowerCase0 ) != -1 ); };
Более эффективный YouCube Т е п е р ь блог Y ou C ub e исп ользует методы классов и и зб ав и л ся о т дублирую щ егося кода. И все это — б лагод аря п р о то ти п ам . Н е важ но , сколько эк зем п л я р о в о б ъ ек та B lo g вы создадите, для всех н и х сущ ествует всего од н а к о п и я м етода. И сам ое зам еч ател ьн о е, ч то с т о ч к и зр е н и я сц е н а р и я блога Y o uC ub e н и ч е го н е изм ен и л ось.
2^т=>екты Blog вы зы ваю т м і-1^ о д ы класса.
alert ( Ы о д [Ор ; К л а сс Blog.
Ы о д [2] .toHTMLО ;
Ыод[3] .containsText("сглЬе") ;
474
глава 10
специальны е объекты
КЛЮ ЧЕВЫЕ МОМЕНТЫ
Класс — это описание объекта, в то время как реализация — это сам объект, созданный по этому описанию. Класс состоит из свойств и методов объекта, в то время как сами объекты помещают в свойства дан ные и дают работу методам.
_
■
Ключевое слово t h i s используется для доступа к объекту из его собственного кода.
■
Объекг p r o t o t y p e позволяет сохранять методы в класс, предотвращая ненужное дублирование кода.
Часзцо
З ад аваем ы е B o T ^ o C jjI
3 * Я до сих пор не совсем понимаю, зачем нужны классы и реализации.
данное свойство объекта; более того, он
вам возможность делать потрясающие
может принять X за переменную. Именно поэтому в конструкторе при создании
Q ; Классы введены, чтобы облегчить создание и повторное использование объ ектов. Единичные объекты можно созда вать в виде литералов, но при этом много ресурсов тратится зря. Ведь этот процесс сопровождается созданием дублирующе гося кода. Вы, как архитектор, который требует перед постройкой очередного типового дома заново чертить ему план.
и инициализации свойств требуется
вещи, ведь некоторые члены сценария требуется поместить на уровень объектов, в то время как для других нужен уровень
ключевое слово t h i s . Совершенно другая природа объекта
классов. 1Мы подробнее поговорим об этом позднее в этой главе.
p rototype.
Он обеспечивает нас механизмом для создания классов. В от личие от таких языков, как C++ и Java, в JavaScript классы не поддерживаются. Они эмулируются при помощи прототи пов. Вы получаете похожий конечный результат, но с применением объекта
А ведь можно создать шаблон и уже по
p rototyp e,
нему получить нужное количество объ емов, сэкономив усилия. Здесь нам на помощь приходят классы — мы исполь
JavaScript. Сохранив свойство или метод
который относится к «скрытым» свойствам всех объектов
зуем один класс для создания нужного количества объектов.
в объекте p r o t o t y p e , вы, тем самым, делаете его принадлежащим к классу, а не к реализации объекта.
Хорошо, классы помогают создать копии объектов. А зачем при этом нужны ключевое слово t h i s и объект
А каким образом в картину клас сов вписываются конструкторы?
prototype?
Чаще всего оно используется для до ступа к свойствам. Скажем, для доступа к свойству X из метода нужно написать
th is
. X . Если написать просто
х, сце
нарий не будет знать, где именно искать
Q ; Имена классов пишутся с большой буквы, в то время как для записи имен объектов используется СтильВерблюда. Ведь реализация объекта является не более чем переменной, а имена пере менных у нас записываются именно так. Некоторая непоследовательность связана с весьма вольным поначалу использо ванием термина «объект». Если быть точным, то имена классов, например
Q ; Как вы уже знаете, за создание объектов в JavaScript отвечают именно
^ ! Ключевое слово t h i s дает доступ к объекту из его собственных методов.
3 * Я немного не понимаю стандарты именования. Иногда имена объектов начинаются с большой буквы, иногда используется нижний СтильВерблюда. Почему так?
конструкторы. Вместе с прототипами они представляют два основных фрагмента головоломки с классами в JavaScript. Конструкторы задают все параметры объ ектов, в то время как прототипы делают то же самое на уровне классов. Оба механизма работают в паре, давая
Blog,
надо писать с большой буквы, а
имена объектов, например или
Ы о д [ О]
b lo g E n t r y
стилемВерблюда.
Вспомните стандартные объекты, с кото рыми мы работали. Текущую дату/время можно было сохранить в переменную (реализацию) с именем создавалась из объекта
now, которая Date (класса).
далее *
475
подпишите здесь... и зд е с ь ... и зд е с ь ...
Подпись В блоге Руби и щ ет и н ф о р м а ц и ю об у в е л и ч ен и и э ф ф е к т и в н о с т и и улучш ении струк туры , к о т о р ы х м о ж н о д о ст и ч ь ср ед ств ам и о б ъ е к т н о -о р и е н т и р о в а н н о го п р о гр а м м и р о в а н и я . В п р о ч ем , ее и н те р е с у е т н е т о л ь к о у со вер ш ен ство ван и е вн у тр ен н его кода, ещ е о н а р е ш и л а д о б а в и т ь к блогу новую ф ункцию . #3^
Вот бы еще под каж дой записью появля лась моя подпись... вот тут вот!
YouCube
- The Blog for Cube Puzzlers^
ube - The Blog for Cube Pimlers
Search
the ttiofl j |
some feUow cubers to discuss ihe piospwt of a 7x7x7 cube. Mixed ' jings. F m i^ * ^ x 7 x 7 cube for sale online. Yikes! That one could be a Iwast. S o l v e s aew cube but of cmrsa, now Tin bored and shopping for a new one. M ^ ^ t o get a headache toiling over toe new cube. Gotta nap.
8/ 14/2008
GoE * c new cube I oKiered. Irs a real pearl. Show All 8;og Ensfies j Iview a RandomJ l o a ,f n ^ Done
---------
Руби думает, ч т о эту задачу м ож н о р еш и ть , д обави в классу B lo g с в о й ство s i g n a t u r e . З ат е м п а р а м е т р ы это го св о й ства зад аю т ся в к о н стр у к то р е и н а ч и н а ю т о то б р аж ат ь ся в каж дой запи си ... и п р о б л е м а реш ен а!
Ш ТУРМ А может быть, подпись следует сделать свойством реализации? Как вы думаете, почему это не самая хорошая идея?
476
глава 10
специальны е объекты _
част°
ЧаДаБаеМые В опросы
3 * Что означает постоянно появ ляющееся словосочетание «объектноориентированный»?
это построение программ из объектов. Вот, скажем, свойство d a t e , используе мое в записях блога, получено из объекта D a te .
0 ! Термин объектно-ориентированный часто используется в программистских кругах, и порой им обозначают разные вещи. В общем случае объектноориентированное программирование —„
Большинство программистов связывают ООП с интенсивным использованием объ ектов в программах. В теории действи тельно объектно-ориентированная
программа может быть разбита на набор взаимодействующих друг с другом объ ектов. Некоторые пуристы даже считают, что иауаЗсг1р1 не относится к языкам ООП. Как сторонники, так и противники такой точки зрения имеют свои весомые аргументы, но пока ни один из них не взял верх.
°S/l4/2oo8 *Яе пеу,
ТТодождите. Разве у Руби не одна и та же подпись? Зачем нам свойство signature для всех объектов?
OS/,g/2oos S o fv e tf tfie п ё
одна и та же п о д п и с ь во веек записях-
‘^^Sfioyyptn ^ ru z z C e ri °S /ie/2008
I A
M anagecC to a e t n S o tta nap.
^ Т^ггСаг Жибу 0S/2I/200S
OS/2g/2ooS
^ ^ ^z C e r Живу
■
Н аверное, одной подписи достаточно.
Зная, что подпись в блоге будет одна и та же у всех объектов, легко сделать вывод, что нам в данном слу чае требуется свойство класса.
6ПОГ
далее ►
477
единожды сохранив
Свойства общего доступа С во й ств а классов п о х о ж и н а м ето д ы кл ассов в том , ч то к е д и н с т в е н н о й к о п и и с в о й с т в а и м ею т доступ все р е а л и за ц и и об ъ екта. С т о ч к и з р е н и я д ан н ы х с в о й с т в а д аж е б о л ее важ н ы , т а к как п о зв о л я ю т всем о б ъ ектам п о л ьзо ваться о д н и м и тем ж е зн а ч е н и е м . И м е н н о такую ф у н к ц и о н ал ь н о с т ь и скала Руби, думая о с в о й ств е s i g n a t u r e , ведь в блоге Y o u C u b e то л ь к о о д н а подпи сь.
Блог
Каждый о б ъ ект сож дняеил свои собст венны е свойст ва.
И зм енени е свойст ва В Ь д .signature^ сразу и з м е н и т свойст ва всех объект ов.
Блог
И зм енени е свойст ва body эт о й записи не окаж ет влияния на С войст во sig n a tu re ' вид д р уги х записей. сохранено в Классе.
Сохраненное один раз свойство оасса доступно затем всем реализациям объекта.
■ . кг.-»'; »;____ I^Met up with some! •fellow cube'iV?
И зм енени е свойст ва d a te эт о й записи п о в л и я е т т о ль к о на ее собст венны й вид.
Н е с м о т р я н а т о ч т о сво й с тв о s i g n a t u r e с о х р а н е н о в классе B lo g , доступ к нем у и м ею т все р е а л и за ц и и о б ъ ек та, к о т о р ы м тр еб у ется п о д п и сь а в т о р а блога.
Как вы думаете, каким способом создаются свойства класса?
478
глава 10
»August 29th,”2008 !
специальны е объекты
Создание сВойстВ класса За всеми этими разговорами о том, где сохраняется свойство класса и какое значение оно имеет, процесс его создания оказывается на удивление обыденным. Это всего лишь одна __ _ строчка кода: -
Д л я д о ст уп а к т а к о м у . сво й ст ву нужно у к а за т ь его название п о сле им ени об ъ ект а и т очки.
Blog, p r o t o t y p e . S i g n a t u r e = " P u z z le r Ruby";
Сначала у к а зы в а е м с я
а ,„ м т н о
С войст ва к л а с са не нуж даю т ся . ° и н и ц и а лизации, но о данном случае эт о и м е е т см ы с л, т а к как м ы уже зн а ем а вт о р а блога.
чж е Ьогада-
p ro to ty p e -
По виду этого кода не понятна его самая интересная особенность —в отличие от кода, создаюш;его свойства объектов, его не нужно помеш;ать внутрь конструктора. Ведь конструктор используется для создания объектов и, следовательно, не умеет создавать свойства классов. Свойства объекта f u n c t i o n Blog(body,
date)
{
Свойство класса t his. b o d y = body; Blog.prototype.
sig n atu re =
С войст ва классов созд а ю т ся вне к о н ст рукт ора с п о м о щ ь ю скр ы т о го об ъ ект а p r o to ty p e .
" P u z z l e r Ruby";
Е динст венная копия подписи на все записи блога.
/7
this.d
ate
= date;
T
Возьми В руку карандаш Напишите код, отображающий значение свойства s i g n a t u r e в от дельном окне. Подсказка: мы предполагаем, что код располагается внутри метода B lo g .
далее >
479
реш ение упражнения
, Возьми Вруку карандаш
V
'ешение
Вот ка к вы глядит код, отображ аю щ ий значение свойства s i g n a t u r e в отдельном окне.
а Iв r t ( t h i s . s i g n a t u re );
Puzzler Ruby
r ~ w
Д ост уп к с в о й с т в а м кл а с с о в , как и к с в о й с т в а м объектов, осущ ест вляет ся п р и п ом ощ и
)
к л ю ч е в о г о с л о в а t h is !
Часзро ^аД аБ аеМ ы е Б о Ц |Э о С Ь 1
А зачем вообще в блоге YouCube сохранять подпись в виде свойства? Почему нельзя сделать ее частью текста записи? ; Разумеется, подпись можно включить в текст каждой записи, но это потребует лишнего времени и усилий, при том что в блог пишет всего один человек. Да и зачем Руби подписывать вручную каждый пост, если есть более простой способ это сделать. Кроме того, это исключает вероятность опечаток. Есть и другая возможность — использовать для подписи строковый литерал в процессе HTMLформатирования текста записи. Такой подход хорошо работает, но в результате важный фрагмент данных — подпись — оказывается зарыт где-то внутри кода форматирования. И при необходимости его не так-то просто найти и отредактировать. Поместив подпись в свойство класса, вы делаете ее легко доступной и, следовательно, легко обнаруживаемой и редактируемой.
3 * Как бы изменилось создание записи, если бы подпись была свойством объекта?
480
глава 10
Q ; Каждая реализация объекта имеет свой собственный набор свойств, инициализированный в конструкторе. Если бы подпись была свойством объекта, конструктору B l o g () пришлось бы задавать ее каждый раз заново. Это несложная задача, так как конструктор просто присваивает свойству строку с подписью. Но при этом создается множество копий, и вы получаете возможность менять содержимое каждой подписи, независимо от остальных.
То есть если я захочу отредактировать блог YouCube таким образом, чтобы туда писали разные люди, стоит ли сделать подпись свойством объекта? ! Именно это и следует сделать, по тому что при таком сценарии свойство s i g n a t u r e должно будет иметь разные значения для разных объектов. Лучше всего решить такую задачу, до бавив к конструктору B l o g {) аргумент, позволяющий передавать в конструктор строку с подписью. Эту строку вы будете использовать для инициализации свой ства s i g n a t u r e каждого из объектов. Другими словами, вы будете работать со свойством s i g n a t u r e точно так же, как и с другими свойствами объекта B lo g .
Свойства классов напоминают глобальные переменные. Чем они различаются? Q ; Свойства классов действительно напоминают глобальные переменные, ведь доступ к ним возможен из любой части сценария. Они даже создаются похожим образом — на уровне главного сценария, вне другого кода. Различие же заключается в том, что эти свойства связаны с классами, а следовательно, и с реализациями объектов. Это означает, что доступ к такому свойству всегда будет осуществляться относительно объекта.
Подождите. Доступ к свойствам классов должен быть выполнен через объекты? Q ; Да, несмотря на то что свойства класса созданы при помощи объекта p r o t o t y p e , доступ к ним осуществляется через конкретные реализации. Для этого используется ключевое слово t h i s , после которого стоит точка и имя объекта. Вся разница только в том, где именно хранится то или иное свойство — в классе или в отдельной реализации.
специальны е объекты
Подписан и доставлен
М ет од toH TM LQ ф о р м а т и р у ет , подпись ка к ч аст ь записи блога.
С оздав св о й с тв о s i g n a t u r e у р о в н я кл асса и п р и с в о и в ему з н а ч е н и е , Руби х о ч е т п о с м о т р е ть , как все р а б о т а ет . В згля нув н а код, ф о р м ати р у ю щ и й зап и сь б ло га для о т о б р а ж ен и я в б р ау зер е, мы обн ар у ж и м код п о д п и си в м ето д е toHTML ().
Blog.prototype.toHTML
= function(highlight)
{
11 используем для выделения серый фон var blogHTML = ЫодНТМЬ
hrghiight , "<Р style^'bao.groun.-color:
" —
■—
this.date.getFuliyearO
^ . "</strongXbr />
=
"<p>"
. .. .................................... ^
. thrs.bo у
^
"</emX/p>"; return blogHTML;
Подпись Руби поя вля ет ся в каждой з а писи.
Теперь сразу видно, кто автор всех запи сей в блоге.
9 /1 д т
Ссылка на свойстлво sig n a tu re уровня класса ничем не о т л и ч а е т с я о т ссы лки на обычное свойст во объект а.
S^9/20ee
h'P uziier Ruby
«liscusstei
prospect o f a 7x7x7
Ш Ш Ш
8/ 19/2008
Руби в о с п о л ь зо в ал ась п р и е м о м и з о б ъ е к т н о -о р и е н т и р о в а н н о го п р о гр а м м и р о в а н и я , ч то б ы р а с ш и р и т ь я зы к Jav aS crip t, доба ви в св о й с тв о s i g n a t u r e к классу B log . Э ти м о н а сделала блог Y o u C u b e ещ е б о л е е л и ч н о й т е р р и т о р и е й . далее >
481
свойство объекта против свойства иласса
Беседа у камина Свойства объектов и классов говорят об обладании данными и се кретных клубах.
Свойство объекта: Т ак э т о о те б е я все в р е м я слышу. Д о л ж ен сказать, ч то я н е п о н и м аю , зач ем т ы нуж ен. Я о т л и ч н о в ы п о л н я ю свою работу, о б ес п е ч и в а я ун и кал ьн о сть о б ъ е к т о в и о тсл еж и в ая зн а ч е н и я и х свой ств.
Свойство класса;
К о н е ч н о , ты эт о д елаеш ь, и это д о ст о й н о во сх и щ ен и я. Н о ты задум ы вался, ч то и н огд а о б ъ ектам н е требую тся и х л и ч н ы е данны е?
С л о ж н о п о в е р и т ь в тако е. П р о д о л ж ай ... Ну, б ы ваю т ситуац и и , когд а ф р а гм е н т ы д ан н ы х яв л я ю т ся об щ и м и для всех о б ъ ектов. К ак с е к р е т н ы й о п о зн а в а те л ь н ы й зн а к в се к р е т н о м клубе. Его зн аю т все ч л е н ы клуба. И есл и кто-то и з н и х и зо б р е т е т с во й о п о зн а в а т ел ь н ы й зн ак , вся с и стем а рухнет. П отом у ч т о кто-то за х о ч ет ему п о сл ед овать, и вско р е н и к т о н е см о ж ет о п о зн а ть друг друга, так как зн ак о в с т а н е т слиш ком м ного. Т о е с ть ты утверж даеш ь, ч то я н е подхож у для х р а н е н и я и н ф о р м а ц и и о с е к р е т н ы х о п о зн а в а т е л ь н ы х знаках? И м е н н о так. Н е о б и ж ай ся, н о все ч л ен ы клуба д о л ж н ы зн ат ь т о л ь к о од и н знак. А могу л и я х р а н и т ь с е к р е т н ы й пароль? В озм ож н о. Если п ар о л ь у каж дого свой , п е р со н ал ьн ы й , т о да, т ы п р е к р а с н о п од ходи ш ь д ля его х р ан ен и я . П р ев о сх о д н о ! Т о гд а я ор ган и зу ю с е к р е т н ы й клуб, и у каж дого и з пас будет с в о й пар о л ь. Н о ведь т ы н е зн аеш ь се к р е т н о го о п о зн а в а т е л ь н о го знака! П р ек р асн о ! А ч т о это вообш;е такое? Н ет, д ей с тв и те л ьн о . Я с е р ь е зн о спраш иваю ...
482
глава 10
специальны е объекты
Hem дублирующемуся коду! Руби не знает отдыха, она решила продолжить ра боту над эффективностью кода YouCube. Она заме тила повторения в форматирующем коде и счита ет, что от них тоже неплохо было бы избавиться, воспользовавшись преимуществами объектноориентированного программирования.
< html> < head> '<Йа.>їо.сиь.
- Т Ь , BIO,
и.
cube
« c t l p t iyp..-t=Kt/3avasciipt-> // К о н с т р у к т о р о б ъ е к т а B i o g f u n c t i o n B l o g (body, date) { l;;i” ! r o r y ^ r b r y " r " N o t h . n g
g o i n g on today.
t h i s . d a t e = date
} возвращаем строковое представление ,g.p r o t o t y p e .t o & t ^ A . ^ - f-u n c t . ,^^.a a
//
-etL?n---“4-"
■d a t e . g e tM o n ;^
( m s ■date ■getFullYear_0
Э т о т код, ф о р м ат ирую щ ий наш и данные, п о вт о р я ет ся.
записи блога
// / / ■ ^ п о л ь з у е м для выделения серый фон var blogHTML - " ;
"<p
style='b a c k g r o u n d - c o l o r :
"<p>";
#EEEEEE'>"
blogHTML += highlight this. d a t e . g e t D a t e 0 ■ < iil
+ LUio.iJ-g
"< 7 ^ r e t u r n b logHTML;
^ ГТ ТТТ/Г ТЧ finore с т р о к а п о и с к а // п р о веряем, = f u n c t i o n (text) ( Blog.prototype.containsText _ _ r e t u r n (this.body. i n d e x O f (text) .
); // З а д а е м п о д п и с ь B l o g .p r o t o t y p e .si g n a t u r e
"by P u z z l e r R u b y ’’
Ш ТУРМ Каким образом избавиться от дубликата форматирующего кода в блоге YouCube?
далее *■
483
место форматирования
М ето д форматирования данных Руби с ч и та е т, ч т о д ля и зб а в л е н и я о т дубликатов ф о р м ати р у ю щ его ко д а нуж но д о б а в и т ь к об ъ екту B lo g ещ е о д и н м етод. В едь ч т о б ы и с п о л ь зо в ат ь о д и н и т о т ж е ф р а гм е н т ко д а м н о го к р ат н о , его нуж но п р е в р а т и т ь в м ето д и л и ф ункцию . А и м е н н о о б ъ е к т B lo g о т в е ч а е т за ф о р м а т и р о в а н и е д ан н ы х как ч асть ф о р м а т и р о в а н и я зап и си блога. И л и нуж но д ей с тв о в ат ь по-другому?
Вернемся к объекту prototype Ч т о м о ж ет б ы ть лучш е, ч ем в зя т ь и м ею щ и й ся о б ъ е к т и усо в е р ш е н с тв о в а т ь его? В едь сущ ествует в о зм о ж н о сть р ед ак т и р о в а т ь ст ан д а р т н ы е о б ъ е к т ы , р а с ш и р я я , тем сам ы м , я зы к JavaS crip t. Э то осу щ ествл яется п р и п о м о щ и о б ъ ек т а p r o t o t y p e . М ы уже и сп о л ьзо в ал и его д ля р а с ш и р е н и я класса B lo g путем д о б а в л е н и я к этом у классу м ето д о в и свой ств. Н и ч т о н е м еш ает н ам п р о д е л а ть ан алоги ч н ую проц едуру с други ми в с т р о ен н ы м и классам и JavaS crip t.
p r o to ty fje ^ ;;" ^
Каждый о ё ь е к т облада е т о б ъ е к т о м p r o to ty p e , п о зво л я ю щ и м дооавлйт(? к нем у сво й ст ва и м е т о ды уровня класса.
484
глава 10
Л ю бой из об ъ ект о в J a v a S crip t.
специальны е объекты
Расширение стандартны х объектов Расш и рен и е стан дартны х объектов осуш,ествляется п р и пом ощ и объ екта p r o t o t y p e . Д ля этого д остаточн о добавить к прототипу нуж ные свойства и методы . В случае в стр о ен н ы х объектов JavaScript резуль татом будет доступ к добавленны м свойствам и методам всех новы х экзем пляров объекта.
Объект prototype позволя ет расширять встроенные о^екты JavaScript.
Строка
Строка
/М етод, д обавл ен н ы й к прототипу встрое н н о го объекта, окажется на уровне класса.
Э тот метод см огут и с п о л ь зо в ать все н овы е объекты, созд анны е на
S t r i n g . p r o t o t y p e s c am ble = f u n c t i o n
осн ове этого класса.
/ / Возвращение зашифрованной строки
J.
Строка
М е т о Э создает ся как член п р о т о т и п а о д ь е к т а S tr in g -
Чтобы в о с п о л ь зо в а тьс я н о в ы м м ето д о м о б ъ е к т а S t r i n g , д о ста т о ч н о вы зв ать его д ля это го об ъекта.
a l e r t ( t h i s . s i g n a t u r e . scrcimble () ); ■ luzPrb uzyRe
Возьми в руку карандаш Напишите код метода s h o r t F o r m a t () , который является расширением стандартного объекта D a te и форматирует дату в виде ММ/ДД/ГГГГ.
далее *
485
реш ение упражнения
Возьми в руку карандаш ’ешение
Вот как выглядит код метода shortFormat ( ) , который является расширением стандартного объекта Date и форма тирует дату в виде ММ/ДД/ГГГГ.
М ет о д добавлен y p a te .p r o to tu p e .s h o r tF o r m a t = functiorJ) { к прот от ипу ^
.......................
о б ъ ект а P a te.
.................................................... ..............................................................................
r e tu r n
i) +
+ this.getPateQ ^ + "/" +- this.getFu!lYear();
ь
Улучшенный блог YouCube Р е д ак т и р о в а н и е о б ъ е к т а Date у в е л и ч и в а е т э ф ф е к т и в н о с т ь сц е н а р и я Y o u C u b e. У п р о щ ается его р е д а к ти р о в а н и е , ведь ф о р м а ти р о в а н и е д ан н ы х т е п е р ь в ы п о л н я е т с я в од н ом м есте, а его д ей с тв и е р а с п р о с т р а н я е т с я н а все за п и с и блога. Р езультаты та к о го р е д а к т и р о в а н и я д ал ек о н е всегда за м е тн ы визуальн о, но о н и улучш аю т код с т о ч к и з р е н и я его д о л го с р о ч н о го и сп о л ь зо ван и я. S a « n y o „ < s id e o f a U > o a l» y s « .« S - s « n .p e d c » y in g c u b c p » z z te s .
Power to ft© puslersl by Pmder Ruby 9 /1 /M 0 8
„ ,n ^ 'J i c i c u h e
S t a r t i n g
W e ^ e a d and oidered the scary 7x7x7 cube. :.tarui g
a m e n ta l e x e rc ise
regiiM sn to prepare. by
Puzzler Ruby c u b « s » d i , c » s s m e p . » t « c . o , a 7 x 7 x 7 cu b e. M ixed
fe e lin g s . by
Puuler Ruby
8 /21Ш Ю 8
Found а 7x7x7
cube fo r sate on lin e. Y ik e s ! T h a t one could be abeasi.
b y P u z z le r Ф орм ат ирование д а т т е п е р ь вы полняет ся п о л ь зоват ельским м ет о д о м объ ект а P a te .
486
глава 10
e c n c w c u b e b u .o ,c o u n e ,n o w
by Puzzler Ruby
I 'm
bo№d anti shopping for a new one.
специальны е объекты
Методы классов
Методы класса имеют доступ только к свойствам этого же класса.
М етод shortFormat {) о б ъ е к т а Date я в л я е т с я принадлежащим классу методом объекта. И м е н н о это д ае т ему в о зм о ж н о сть ф о р м а ти р о в а ть с о х р а н е н н ы е в о тд е л ь н ы х о б ъ е к тах даты . Н о м ож н о со зд ать и метод класса, к о т о р ы й не будет и м е т ь доступа к с во й ствам о б ъ екто в . Д о сту п н ы м и для н и х окаж утся т о л ь к о св о й ства классов, т а к и е как, н а п р и м е р , св о й с тв о signature класса Blog.
Блог Блог
fviewc>3b! классов ы м е н зт д о с т у п К c6oiXcwSo.M
М ет оды классов не иллр.т1лл д о ст уп а к сво й с т ва м и м е т о д а м объект ов.
Реализация
Д л я со зд ан и я м ето д а класса о б ъ е к т prototype н е нуж ен —д о с т ат о ч н о н а зн а ч и т ь м ето д классу, указав и м ен а класса и о б ъ ек та, как п о к азан о ни ж е.
Biog.showSignature =
functionO
Д л я д о ст уп а к сво й ст ву класса т а к о м у м е т о д у понадобит ся свойст во о б ъ ект а p r o to ty p e .
{
alertC'This blog created by " + Blog.prototype.signature +
};
\
Т ак к ак м ето д ы классов н е и м ею т св я зи с о тд ел ьн ы м и об ъ ектам и , для и х в ы зо в а д о ст а т о ч н о со сл аться н а и м я класса. Т а к о й м етод м о ж е т б ы ть в ы зв ан и о б ъ екто м , но д ля эт о го п о тр еб у ется указать и м я класса.
Так как sig n a tu re — э т о свойст во класса оно дост уп но для наш его м ет ода.
B l o g .showSignature
Д л я вызова м ет о д а класса нужно у к а за т ь и м я эт о го класса.
Ш ТУРМ Существует ли код блога YouCube, который имеет смысл сделать методом класса Blog?
далее >
487
и снова о классе Blog
А нельзя ли использовать метод класса для сорти ровки записей блога?
Пересмотр процедуры сортировки Я
И д ея п е р е с м о т р а с о р т и р о в к и н е л и ш ен а и н те р е с а , потом у ч то ф у н кц и я, осущ ествляю ш ;ая проц едуру с р а в н е н и я , и г р а е т нем а лую р о л ь, связанную с о б ъ екто м Blog. В н а сто я щ ее в р е м я о н а п р е д с та в л я е т с о б о й л и т е р а л вн у тр и ф у н кц и и showBlog ().
C O 'P '^S б»*'«
function ShowBlog(numEntries)
l3io3-
-—
{
// Сортируем записи блога в обратном хронологическом порядке
Ыод. sort (function{blogl, Ыод2) { return Ыод2.date - blogl.date; });
}
В п олн е возмож но п е р е м е с т и т ь код сравнения 8 м е т о д класса. О д н и м и з ф у н д ам ен тал ьн ы х п р и н ц и п о в о б ъ е к т н о -о р и е н т и р о в а н н о го п р о г р а м м и р о в а н и я я в л я е т с я с в я зь ф у н к ц и о н а л ьн о ст и о б ъ ек та с сам им о б ъ екто м . Д ругим и словам и , н е следует о с т ав л я т ь н а откуп внеш нем у коду д ей с тв и я , к о т о р ы е о б ъ е к т м о ж ет в ы п о л н и ть сам о сто я тел ь н о , в д ан н о м случае с о р т и р о в к а за п и с ей в п о л н е м о ж ет вм есто ф у н кц и и showBlog () в ы п о л н я т ь с я с р ед ствам и сам ого об ъ екта. Н о н ел ьзя л и п о м е с т и т ь о сущ ествляю щ ий эту проц едуру м етод в класс Blog? Д л я о т в е т а н а д ан н ы й в о п р о с нуж но п о н я т ь , тр еб у ется л и этом у методу доступ к д ан н ы м и л и м етод ам о тд ел ьн ы х о б ъ ектов.
488
глава 10
специальные объекты
Функция сравнения Е д и н ств ен н ы м сп о со б о м о т в е т и т ь н а зад ан н ы й в к о н ц е преды дущ его р азд ел а во п р о с я в л я е т с я а н а л и з ф у н к ц и и с р а в н е н и я . В от соответству ю щ и й л и тер ал : _Дбй о б ъ ект а Ыод п е р е ' д а ю т ся ф ун кц и и в к а ч е с т ве а р гу м ен т о в. function(blogl, blog2)
{
return blog2.date - blogl.date;
П роцедура сравнения сводит ся к вы чит анию а р гу м ен т о в.
■ Ч _________
}
Х о тя ф у н кц и я и и м е е т д ел о н е п о с р е д с тв е н н о с о б ъ ек там и , о н и п ер ед а ю т с я ей в к ач еств е аргум ентов. Э то совсем н е т о ж е сам ое, ч т о п о п ы тк а д оступа к св о й ствам и л и м етод ам о б ъ е к т а п о ср ед ств о м кл ю ч ев о го сл о в а t h i s , н е в о зм о ж н ая и з м етод а класса. С о о т в е тс т в е н н о , м ы видим , ч т о ф у н кц и и с р а в н е н и я н е нуж ен доступ к о б ъ ектам , и э т о д ел а е т е е п р е к р а сн ы м кан ди да том н а п р е в р а щ е н и е в м ето д класса.
О б ъ ект .
Б о л е е т о го , э т о й ф у н кц и и н е тр еб у ю тся д аж е с в о й ст в а класса, х о т я о н а и и м е е т к н и м доступ. М ет од класса п р и необ хо д и м о ст и и м е е т д о XOOUMU!.-vvw с т у п к сво й ст ву класса.
f /
^ —“ —— — п уункции н к ц и и со р т и р о вки Ф а&-Юлрс6.у&шг.я д о с т у п к данны м о б ъ ект а или класса. function (blogl, Ыод2) { return blog2.date - blogl.date;
К ласс,
Если бы ф ун кц и и с о р т и ровки т ребовался д о ст у п к о б ъ е к т а м , создание м ет о д а класса ст а л о бы невозмож ным.
Возьми в руку карандаш Перепишите код функции сравнения, превратив ее в метод класса B lo g и присвоив ей имя b l o g S o r t e r {).
далее >
489
мет од класса? вот он!
Возьми в руку карандаш Решение
Вот как выглядит функция сравнения записей блога YouCube после превращения ее в метод класса Blog.
J M o g M q g S g rte r ,-,
£.
...r ^ t'^ fn bJogZ.date, - blogi-.date; }; ^ о ^ р о в к а т е п е р ь вы п о лн яет ся м е т о д о м класса Blog, ко т о р ы й на зы вает ся blogSorterQ .
ВызоВ метода класса П р еи м у щ ества п р е о б р а зо в а н и я ф у н кц и и с о р т и р о в к и зап и сей б л о га в м етод Blog ст ан о в я тс я б о л ее я сн ы м и , есл и п о с м о т р е ть н а код в ы зо в а эт о го м етода. function showBlog(numEntries) { // Сортировка записей блога Ы о д . sort (Blog.blogSorter)
Д ет али сорт иров ки за писей т е п е р ь ■от даны на о т к ц п м е т о д у blogSorterQ класса Blog.
} П р е л е с т ь это го ко д а о т к р ы в а е тс я н е сразу. Д ел о в том , ч т о т е п е р ь с о р т и р о в к а за п и с е й б л о га в ы п о л н я е т с я н е в н еш н ей ф у н к ц и ей showBlog О , а внутри класса Blog, к ко то р о м у эт а п р о ц ед у р а л о ги ч еск и п р и н ад л еж и т. П р и м е ч а т е л е н т о т ф акт, ч т о с о р т и р о в к а по-п реж нем у и н и ц и и р у е т ся в н е класса Blog ф у н к ц и ей showBlog ( ) , и эт о и м е ет см ы сл, так как д ан н а я п р о ц ед у р а в л и я е т н а все за п и с и блога. Н о о с о б ен н о с т и с о р т и р о в к и о тд ел ьн ы х за п и с ей бло га тако в ы , ч т о эту задачу м ож н о р е ш и т ь ср ед ств ам и класса Blog. Х о р о ш и й О О П -д и зай н зачастую акк у р атн о с о ч е т а е т о б ъ е к т ы и окр у ж аю щ и й и х код.
Блог
showBlogO
490
глава 10
специальные объекты
В Картинка с т о и т тысячи слоВ Руби п р о д о л ж а е т в о с т о р га т ь с я у с о в е р ш е н ств о в ан и ям и св о его бло га Y o u C u b e, н о п о д о зр е в а е т, ч то ч и т ат е л и вряд л и см огут р а зд ел и ть ее энтузиазм . Ведь п о к а ч то все в н е се н н ы е и зм е н ен и я н и как н е п о в л и я л и н а в н е ш н и й вид блога. П о это м у Руби р еш и л а, ч то п р и ш л о в р е м я д о б ав и ть ч то-то б о л ее за м е тн о е н ев о о р у ж ен н ы м глазом!
Руби х о ч ет сдел ать так, ч то б ы каж дая о тд ел ьн ая зап и сь п о д д ер ж и в ал а в о зм о ж н о сть вставк и и зо б р а ж е н и й , к о т о р ы е будут д ем о н с т р и р о в ат ь с я вм есте с те к с т о м и д ато й . Т ак как к а р т и н к и тр еб у ется в ставл я ть д алеко н е всегда, д ан н ая ф у н кц и я д о л ж н а б ы ть н е о б я за тел ь н о й . Э то т ак ж е п о зв о л и т с о х р а н и т ь п е р в о н ач а л ь н ы й вид уже имею ш ,ихся зап и сей .
Ш ТУРМ Каким образом включить поддержку изображений для объекта B l o g ?
далее
491
карт инки — это всё
Bcmaßka изобра)кений Ч т о б ы д о б а в и т ь в о зм о ж н о с ть встав к и и зо б р а ж е н и й в за п и с и б ло га Y o u C u b e, н ам надо п о п ять, каки м о б р азо м в н е д р и т ь н о вую структуру в о б ъ е к т Blog, н е и зм е н и в с п о со б а его ф у н кц и о н и р о в а н и я . П о этом у поводу в о зн и к а е т д ва воп роса:
Каким образом лучше всего сохранить изображение в объекте Blog?
Как добавить к блогу необязательную воз можность вставки изо бражений?
Н е за в и с и м о о т т о го , каким о б р азо м будет с о х р а н е н о и зо б р а ж е н и е , о н о о т о б р а ж а е т с я н а с т р а н и ц е п р и п о м о щ и т е га < 1 тд > . Д о с т а т о ч н о у к а з а т ь им я ■ф а й ла с изображ ением.
' <img src="cube777.png” />
Э то т ко д п о к а зы в а ет нам , ч т о с т о ч к и зр е н и я блога и зо б р а ж е н и е — эт о т о л ь к о стр о ка. Р азум еется, о н а ссы л ается н а ф а й л с к а р т и н к о й , х р а н я щ и й с я где-то н а с е р в е р е , н о д ля о б ъ е к т а Blog о н а все р ав н о о с т ае т с я с тр о к о й .
io o tli
UiOlOC o oi ö lo toiom
П о этом у и зо б р а ж е н и я к об ъекту Blog м ож н о д о б ав и т ь как св о й ство , х р а н я щ е е строку, а н а л о ги ч н о е свойству body.
cube777.png
Г Изображ ение кубика р а зм е р о м ^Р'^^^итлся о ф а й ле с и м е н е м сиЬ е7 7 7 .р п д.
492
глава 10
Для объекта Blog изображение — это не более чем строка.
С войст ва body и im age кра н ят ся в о б ъ ект е S lo g , как ст р о ки
Блог
специальные объекты
Необязательное изобра}кение И та к , в о б ъ е к т е B lo g и зо б р а ж е н и е с о х р а н я е т с я в ви д е с т р о к о в о го свой с тв а im a g e , н о о с т ае т с я в о п р о с , каким о б р азо м сдел ать эту проц едуру н е о б я за те л ь н о й . Ч т о б ы о т в е т и т ь н а н его , в е р н е м ся к кон струк тору, как к месту со зд ан и я и и н и ц и а л и за ц и и о б ъ екто в. И м е н н о туда следует п о м е ст и т ь о с о б ы й код, указы ваю щ и й н а н е о б я за те л ь н о с т ь н о в о го свой ства.
f u n c t i o n Blog(body,
date)
(
А что случится, если не передавать конструктору аргумент? Может быть, свойство просто получит значение null?
// н а з н а ч е н и е с в о й с т в t h i s . b o d y = body; t h i s . d a t e = date;
}
О т с у т с т в у ю щ и е аргументы р а в н ы нулю.
Н е п е р е д а н н ы й в ф ункц ию м ето д и л и н е п ер е д а н н ы й к о н структору аргум ент для л ю б о го кода, к о т о р ы й п о п ы тае т с я его и сп о л ьзо в ать, будет и м е т ь зн а ч е н и е n u l l . В случае с к о н стр у кто р о м эт о о зн а ч а е т п р и р а в н и в а н и е к n u l l св я зан н о го с аргум ентом сво й ств а, ч т о в о в се н е плохо. Г л авн о е п р и этом н е заб ы ть п о м е с т и т ь н е о б я за те л ь н ы й аргум ен т в сам ы й к о н ец спи ска, ч то б ы н е в о зн и к а л о путан и ц ы . Э та те х н и к а р а б о т а е т д ля лю б ы х ф у н кц и й и м ето д о в, н о о с о б ен н о о н а п о л е зн а для ар гу м ен та im a g e в к о н с тр у к то р е B lo g () .
Возьми В руку карандаш Перепишите конструктор B lo g () таким образом, чтобы он начал поддерживать необязательное свойство image.
далее >
493
реш ение упражнения
в руку карандаш,
'ешение
Вот ка к вы глядит ко н с т р у кто р B l o g ( ) , поддерж иваю щ ий необязательное свойство image.
.
і .........
.
.
.
,, . ;
с в о й с т в о image,, и е м у при сво ен а р г у м е н т im age.
. ,
. ,
,
J
M , - d . t e =.
.
А ргум ент Ы ааг добавлен в J :Z 7 T Z Z Z ? конец списка '^^Р^даваем ы х х ™ < :« г а к т о „ „
............................................
, th is.im age = image; }
_
Ч асто
^аД аБаеМ ы е B o iij^ o c b i Обязательно ли ставить аргумент im a g e на последнее место в списке
Добавление галереи Н о в ы й б л и стат ел ь н ы й к о н стр у к то р B l o g ( ) , п о д д ер ж и ваю щ и й вставку и зо б р а ж е н и й , б есп о л езен , есл и его н е п р и м ен я ть . В от как в ы гл яд ят этап ы со зд ан и я за п и с и с кар ти н к о й :
передаваемых конструктору B l o g () аргументов?
Н а с е р в е р е п о м ес ти те г р а ф и ч е с к и й ф а й л в ту ж е папку, ч т о и стр ан и ц у Y ouC ube.
Q j Да, ведь изображение относится к необязательному фрагменту записи. Весь вопрос тут в способе передачи аргументов функциям. Если функция имеет два аргумен та, можно передать ей оба, только первый или ни один из них. Но невозможно передать только второй аргумент. Именно поэтому необязательные аргументы ставятся в самый конец списка. Также имеет смысл более важные аргументы ставить в самое начало. Так как а р гу м е н т іт а д е
©
С о зд ай те новую зап и сь к ак о б ъ е к т B l o g в коде с ц е н а р и я Y ouC ube.
является для конструктора B l o g () необя зательным, мы ставим его в конец списка, где им легко пренебречь,
Блог
V\W ow, it tôoi?me;al
09/19/2008
couple of weeks b u t ^ — —J. ‘Л О Д
ber 191И5'20Щ
494
глава 10
специальные объекты
В р езу л ьтате м ы получим код, к о т о р ы й со зд ает новую запи сь, п е р ед а в ая с т р о к о в о е с в о й ств о i m a g e в п о с л е д н и й аргум ент к о н с тр у к то р а B l o g ( ) : new Blog("Wow, it took me a couple of weeks but the new cube is finally solved!' new Date("09/19/2008"), "cube177.png")
г.
Изображ ение п е р е д а е т ся в последний а р г у м е н т к о н с т р у к т о р а BlogQ-
Отобра)кение картинок Т еп ер ь , когда за п и с и бло га сн аб ж ен ы к а р т и н к а м и , о стал ось од н о , п о сл ед н ее у со в ер ш ен ств о в ан и е. В есь э т о т р а зг о в о р о к о н стр у кто р ах и н е о б я за те л ь н ы х ар гу м ен тах н е и м е ет осо б о го зн а ч е н и я , если отображ аю ш ;ий зап и сь код н е у ч и т ы в ает н о в о е св о й ств о i m a g e . Э то т код р а с п о л о ж е н в м ето д е t o H T M L ( ) . И м е н н о д ан н ы й м ето д о т в е ч а е т за H T M L -ф о р м а т и р о в а н и е за п и с ей блога, но т е п е р ь о н д о лж ен п р и н и м а т ь во в н и м ан и е св о й ств о i m a g e , как и м ею щ ее зн а ч е н и е , т а к и б ез него. В д ан н ы й м о м е н т п о я в и л о сь два с п о со б а о т о б р а ж е н и я зап и сей , и и х в ы б о р за в и с и т о т н а личия картинки.
Г
Т еперь от ображ ение за писей блога б удет о с у щ ест в ля т ь с я в с о о т в е т с т в и и со следую щ ей логикой.
If (картинка есть) Отобразить запись с картинкой Else Отобразить запись без картинки
Возьми в руку карандаш в м е то д е
t o H T M L () о б ъ е к т а B l o g о т с у т с т в у е т ф р а гм е н т
кода, о т в е ч а ю щ и й за о т о б р а ж е н и е к а р т и н о к . В п и ш и т е е го и с н а б д и те п р и м е ч а н и я м и .
if (
) {
blogHTML += "<strong>" + this.date.shortFormat() + "</strong><br / X t a b l e X t r X t d X i m g src='" + this, image + " '/ x / t d x t d
stYle='vertical-align:top'>" + this.body + " < / t d X / t r X / t a b l e X e m > "
this .signature + "</emX/p>";
} else { blogHTML += "<strong>" + this.date.shortFormat() + "</strongXbr />" + this.body + "<br /><em>" + this.signature + "</emx/p>";
}
далее >
495
реш ение упражнения
Возьми в руку карандаш Решение if (
tkis.im age
' ................
^
Вот как выглядит метод toHTML () объекта Blog после вставки в него фрагмента кода, отвечающего за отображение картинок.
~~
I <
— — -----— - Если свойстВц image присвоена
ссы лка на изображ ение, р е з у л ь -
ы„,нт«ь *=
'
"</strongxbr / X t a b l e X t r X t d X i m g src="' + this.image + " ' / x / t d x t d style='vertical-align:top'>" + this.body + " < / t d X / t r X / t a b l e X e m > " + this .signature + "</emX/p>";
else {
^ ./^
Ч-
—
В п р о т и в н о м случае за п и с ь по ка зы ва ет ся ° обычном виде, без карт инок.
blogHTML += "<strong>" + this.date.shortFormat() + "</strongXbr />" + this.body + "<br /><em>" + this.signature + "</emx/p>";
Блог на основе объектов Руби в экстазе. Б л а го д а р я о б ъ ек там е е б лог р а с т е т и со вер ш ен ств у ется, а т е п е р ь к нем у ещ е д о б ав л ен а ф ун кц и я п о к а за к а р т и н о к , к о т о р а я н е с о м н е н н о д о л ж н а п о н р а в и т ь ся п о сети тел я м . 0 f! 0
¥оиСвЬа_- The Sloe fw C ute 1»игг1е « _
YouCube The Blog for Cube Puariers
Search the Biog | |
9ЛЧЙШ®
З а п и с ь с и зо бражением.
Wo«, it шок a® a coaple of w «ks tat the new cubc ^ * solved!
li
byPuzzkrRuby
G o S n c w 7x7x7 cube. Could be my last blog post for a while...
byPuukrRuby At»nde<i a raUy outside of a local »>' store Sia stopped carrying cubc puzzles. Power to aiepffittoi by Puzder R u b y
496
глава 10
....................
^
специальны е объект ы
I Согните страницу по вертикали, ч т о б ы совместить два мозга и р е ш и т ь задачу.
Вкладка Что дают объекты большинству сценариев
M issing Image
deliver()
і /Л - -
1
:
Объекты добавляют к сценариям так много потрясающих вещей, что сложно выбрать что-то одно. Некоторые объекты вьщеляются из общей массы, что осложняет задачу. Но ответ очевиден!
jJ
0 хо 1л а н а оШ иёки
Когда сценарий не работает ^ ( у ( V
Никогда не знаешь заранее... Иногда все работает, и все счастливы... А потом — бах! И все плывет. Главное — чтобы рядом оказался такой парень, кок я, который все починит.
Даже самые лучшие планы в иауаЗспр1 иногда не реализу ются. и когда это происходит, главное — не паниковать. Лучшие програм мисты не те, которые никогда не делали ошибок, — на самом деле это про сто лгуны. Лучшие — это те, кто может успешно обнаружить и устранить ошибку Отладчики высокой квалификации нарабатывают хорошую манеру написания кода, минимизирующую вероятность появления неприятных оши бок. Лучше предотвратить, чем потом бороться. Тем не менее ошибки то и дело встречаются, и вам нужен арсенал средств борьбы с ними...
дефект...
какая гадость!
Устранение дефектов Ш о ки р у ю щ и й ф а к т и з ж и зн и сл ад о стей — с т ан д ар т ы н а п р о и зв о д с т в о ш о к о л ад н ы х б ат о н ч и к о в н е о т н о с я т к б раку о ко л о 60 р а зн о о б р а зн ы х д е ф е к т о в в п л и тк е. А во т б о яться б р ак а в ко д е Jav aS crip t п р и ч и н н ет. Э то т код к о н тр о л и р у ет с я б о лее тщ а те л ьн о , ч ем о б о р у д о ван и е для п р о и зв о д ст в а ш околада. С ущ ествует д аж е с п е ц и а л ь н а я р а б о ч а я группа д ля у с т р ан ен и я д еф е к т о в JavaS cript.
BUG SCENE INVESTIGATORS К т а к о й группе н ед ав н о п р и с о е д и н и л с я О уэн в ка ч е ств е т е с т и р о в щ и к а JavaS crip t. Ему н е т е р п и т с я п о к а за ть с во и р а б о ч и е н ав ы к и , у стр ан и в как м о ж н о б ольш е о ш ибок. О уэн , т е с т и р о в щ и к J a v a S c n p t и бывший лю бит .ель ш околада.
^олньШ д е ф ек т о в Н а пути к успеху Оуэну п р е д с то и т р е ш и ть н е скол ьк о задач. Ему п р ед с т о и т о в л ад еть н е п р о ст ы м искусством б о р ь б ы с де ф ек т н ы м кодом Jav aS crip t, и т о л ь к о то гд а о н см о ж ет д о ст и ч ь н а м е ч ен н ы х вы сот.
500
глава 11
одскаЗК а
продовольственным стандартам, шоколадный батончик может иметь около 60 раз нообразных дефектов. А вот когда дело доходит до ошибок в коде JavaScript, люди в В51 проводят политику абсолют ной нетерпимости, и это правильно.
охота на ошибки
Проблемы с калькулятором для Ю с р е д н и й
П ер в ы м делом О уэну п о р у ч и л и р а зо б р а т ь с я со сц ен ар и е м , вы ч и сл яю щ и м Щ н а о с н о в е м асси ва д ан н ы х и со ставл яю щ и м группы и з пользо-
С качат ь ф а й лы , с к о т о р ы -
в а т ел е й со схо дн ы м и р езультатам и. В зяв за о сн ову м ассив ч и сел , эт о т сцен а р и й в ы ч и с л я е т ср е д н е е и у казы вает у р о в е н ь и н т е л л е к т а эт о го ср ед н его .
^ headF4rstla h s.c o m /b o o k s/h fjs/.
Оуэну р ассказал и , ч т о с ц е н а р и й со д е р ж и т м н о ж еств о ош и б ок. К со ж ал е н и ю , в о сн о в н о м о н и о п и с ы в а л и сь ф р а з о й , «оно н е р аб отает».
г 11-, 97 86, 75, 92, І1 4 1 б 5 , '9 6 , 97, 88, 108 1;
Для отладки далеко не всегда дают грамотно написанный код.
далее >
501
скажи мне, что у тебя за браузер?
Различные баузеры Ф - BS! C ase t ; 10. C ^ c u la to r,
О уэн думает, ч т о п о н я т ь пр о б л ем у ему п о м о ж ет п р о го н с ц е н а р и я в р азл и ч н ы х браузерах. И н а ч и н а е т с б р ау зер а In te r n e t E x p lo rer...
I n ^ r n e t & p lo i
In te rn et Explorer
в
Д в о й н о й щ елчо к на жел~ п^ом значке в ниж нем ле в о м у г л у браузера 1Е о т к р ы ва е т окно ош ибок
«■шясиигч ^5Й»fijttse. ■ÖÄÄjte-^с^агщЙтеwaBW4icajdf^^5«di D §««^<ё№*»'1Ь5шем^ч(ймг!Вйздйсэпийгаи f. ~0k'"'.1
R e a d v t o c a lc r f a t e th e a \ « - a g e I Q .
|цО«»е;
"iwyo
üfw.53
Oar %
'«js'isiÄ«tefined
в I n te r n e t E x p lo re r со о б щ е н и е об о ш и б ке ПОЯВЛЯС'1 'СЯ при п е р в о й загрузке с т р ан и ц ы , н о О уэн н е у в ер ен , 'гго ему м ож н о д о в ер я т ь . Д о с та т о ч н о взглянуть н а код, ч то б ы об н ар у ж и ть п ер ем ен н у ю i q s , в то в р е м я как б р ау зер г о в о р и т о ее отсут стви и . З н ая , ч то б р ау зер ы д ал ек о н е всегда п р ав и л ь н о со о б щ аю т об о ш ибках, О уэн р е ш а е т п о п р о б о в а т ь Safari...
C<Käe:S I URL Яв:\//^;Л)всыте«8Й20в«й£2Шй0П9»М1Ым^*
-Si
В коде п ер ем ен н а я оп р ед елен а , п о э т о м у ош ибка каж ет ся лиш ен ной см ы сла.
Safari SyntacError - Pars«
ft’sf^#U«fjf»Fnrh*s!/DMum»Wj!'«Eisrfirst/i*»|MTll
Сая’1(tndwiabte:los
Un.- 2i
t®*: 53
Найдя ст р о ч ки ,
Rsady и calculate the average [Q.
J
Б р ау зер Safari п о к а зы в а ет н а ош ибку в совсем д ругой с т р о ч к е, н о О уэн н а п е р в ы й взгляд н е в и д и т там н и ч е г о к р и м и н ал ь н ого . П о это м у о н р е ш а е т п о п р о б о в а т ь ещ е раз, в б р ау зер е O p e ra ...
Opera
/ J
При т о м ч т о ном ер ст р о ки д ает ся уж е д р у гой, код ош ибки совпадает с показан ны м в Safari.
С(ОаетЫ
)avaS!Spt-Ss,Vfec«#4>ö.A::^S>cumen»%3:«id%2DSetthgsM*ft^%ZW orreon,-ü^^^ b * i e scnpt canpöfeon Synax üTor ft+de iaaA^;ine 71 of irAw ж п Щ a t fte:/^.^.ost,'C^Ajocijwsnis%20er>d«,20SeUings/Mid58e»%2Qf^.,
etse>fsv«?ece<50 •;^/"«>ia!ho9t^::Ä>ftM T)№ t9%20ar«j%2ö^ttngs;'M ichael%204o<-,5on^34sktop/b9.^S9e3_l,M ml Е-да! tt»ead: iosw О кно E rro r Consoles дает возм ож ност ь ^•^агност ироват ь про б лем ы с к о дом J a v a S c rip t.
502
глава 11
Emjr;
name:ЯеЛв’в^сесг.'ог iTwssaee: Stetwnerrtooline i: Refe-ence tosjndefined -.агиЫе; s#wwi<^3ess Secktrece;
uoe iof sfföt
st»ftb3CaKfiQs'5:
Al {jritnvuntocabon tstaffnwnt source i»de not e v a il^ J
б раузера S a fa ri ^ 1 ^ а л а с ь ош ибка вы f j ^ f y x u m e , чт о осе в порядке.
охота на ошибки
П р о и с х о д и т ч то-то с т р ан н о е . O p e ra п о к а зы в а ет д ругой н о м ер с т р о к и , н о п р и этом в о с п р о и зв о д и т код, п о к а за н н ы й Safari, ч то для О уэна, к о н еч н о , х о р о ш о . Д ру гое д ел о , ч т о о н н е в и д и т в это м коде н и ч е г о кр и м и н ал ьн о го , и п оэтом у р е ш ае т п о п р о б о в а т ь еш;е и F irefox... Firefox п о м о г а е т о6нару>^<ип\ь п р и р о 1^ Эу ошибки. BSI Case 1: tQCaicuJatof __ 0 О О,.. F ir e fo x
Firefox ука зы ва ет нд совсем д р у гой н о м ер с т р о ки с п р о б лем н ы м кодом.
trror Console
fii * Atl
m
ih Wafnings
Error*
ErroR Soi4rc«riie:
calculate the average IQ.
#
Messages
{befsffi
Clear
^
^
eiae if .avsrage « SQ <
<htmi> <head>
Do
<tltle>BSI Case 1: IQ Caloulator</title>
;»rsr;r.rs:>„, f<Jnction showIQClass (data)
(
dOOuJnt!get\llentBy?d?"outpuj™ .innerHTML; = "You ralcIQClass(data) ).innerHTMr. function calcIQClass(data)
Xa! Я ду маю, что вижу проблему.
(
'°aviL“ e ^ :
'
- e r a g e . Math.noor,average
/ data.length);
if )
Should
else if average < 50 {
their tvs";
^
”
else If (average < 70) ( )
“Should hit the boo.s";
Firefox п о д т верж д ает , чт о э т а cm poK aj я вля ет ся и с т о ч н и ко м ошибки.
else If (averag < 81) ( < ®lse if (average < 9i) ^
“ "--r
. r a m exercises
, - t u r n ..people „ho could .e considered dull.... else If (average < m j )
,
"people Of average lntelllg,„,,,,.
else if (average < i2i) , .
" P - P ^ e Of superior intelligence..;
else if (average < 141) ( J J^eturn ..people of very superio else {
• intelligence"
Ш ТУРМ
return ..geniuses..;
Какую ошибку обнаружил Оуэн при помощи всех этих браузеров?
</script> </head>
I K “—
„ далее >
503
достоинства Firefox
Firefox считается наиболее подходящим для устранения дефектов браузером, по крайней мере, в настоящее время.
Firefox-cnacumeAb О б н аруж и в, н аск о льк о т о ч н о F irefo x о п и сал ош ибку, О уэн р еш и л и дальш е п о л ь зо в а тьс я его помош;ью. О н щ елкнул н а ссы л ке в к о н со л и о ш и б о к и о казал ся н а с т р о ч к е, п р ед ш ествую щ ей п о д о зр и те л ьн о м у коду.
ЦоДсКаЗКа
Firefox не только хорошо обнаруживает дефекты кода, но еще и оснащен расширением Firebug, выводящим отладку на совершенно новый уро вень. Вы можете бесплатно скачать это расшире ние по адресу http://w w w .getfirebug.com /.
EfforConsote
II
J.
E r ro r s ,
W a r n in g s
У M essages
________
» : _ С *е а г
На в т о р у ю ош ибку пока не о б раил,айтле в н и м а н и я — будем р а с с м а т р и в а т ь их по одной за раз. <Ьеа^> <Ьеаа> П оследовав по ссы лке, вы у ви д и т е код веб -ст р а н и ц ы . Строчка,, п р е д ш е ст ву ю щ а я п о д о зр и т е л ь н о й , б уд ет выделена.
—' case Ь ха
f u n c tio B ^ h o w I ( 3 C la s s { d a ta »
}
*
ddocuaintfeetSlLMtByld o c u J n t f e e W l L M t B y l d ? «г ™ * ut« äiiS
«IclOClasstdatai I
fu a c tio a c ftlc io c la s s (d a ta )
• ■' >>••;
{
« - a ,. . П ричиной п роб лем ы я в ля ет ся в о т э т о т код.
o f tJ ,e J re t« ,
" p e o p le wbo . h o u l 4 k i l l t b . i . w . - ,
e l s e i f a v e r a g e « S* / ____ _ G ise i f
{average < 7 0 ) /
}
“ bo s h o u ld h i t t h e
e ls o i f (a v e ra g < 81) | -v ^ r e t . « - p o o p l . „ h o S h o u ld c o n s i d e r b r a i . ^ Д.1ДР ;{
f a v rir a q e <
■■
:cises"
Lif»e2S,Cor i А нализи руя п о к а за н н о е б р аузером F irefo x с о о б щ ен и е об ош и б ке, О уэн о б наруж ил, ч то б р ау зер Safari п р а ви л ьн о указал н о м е р о ш и б о ч н о й с т р о к и (25). F irefo x вы д ел и л и упом янул строку 24, н о п р а в и л ь н о п ок азал, ч то о ш и б ка со д е р ж и т с я в с т р о к е 25. И ч т о н ам н ого в аж н ей , F irefo x о б ъ ясн и л , ч т о и м е н н о н е в п о р я д к е с кодом .
504
глава 11
*
e l s e i f a v e r a g e < 50 {
В о п е р а т о р е if п р о вер я ем о е усло ви е забы ли за к л ю ч и т ь о скобки.
охота на ош ибки
Часто Задаваем ы е Б о і ї р о с ; і ,і
• Где находится консоль в моем браузере? Q ; к сожалению, все браузеры разные, и иногда обнаружить консоль для просмотра ошибок JavaScript не так-то просто. Например, браузеры Safari для компьютеров Макинтош дают доступ к консоли только через меню Debug, доступ к которому по умолчанию отсутствует. Для получения доступа введите
Он превосходит другие браузеры в умении находить дефекты в коде сценариев и указывать на них. Возможно, в будущем и другие браузеры смогут выполнять данную функцию так же хорошо, но в настоящее время именно Firefox является самым мощным инструментом для отладки сценариев JavaScript.
3*
На какую ошибку указывал Internet Explorer?
в приложение Tenninal следующую команду (в одну строчку):
defaults write c o m .apple.Safari IncludeDebugMenu 1 Если у вас другой браузер, почитайте документацию, там должно быть написано, как открыть консоль. В браузере Firefox она открывается командой Еп'ог Console из меню Tools.
! Этого, к сожалению, узнать нельзя. Дело в том, что код сценария был загружен некорректно, и поэтому ошибка, о которой сообщает Internet Explorer, — это результат неверной работы интерпретатора JavaScript. О некорректной загрузке можно судить по тому, что переменная i q s была указана как «неопределенная», в то время как код ясно показывает процедуру создания i q s .
! Что делает браузер Firefox таким особенным?
Напрашивается вопрос: содержит ли сценарий и другие ошибки и что на самом деле означает термин «неопределенный»?
; Разработчики этого браузера проделали большую работу и дали своему детищу большие способности к поиску ошибок.
Несло)кная отладка О уэн счастл и в о т сто л ь б ы ст р о го за в е р ш е н и я п о и с к а о ш и б ки в к ал ьк у л ято р е Щ . С л егко стью в н еся и с п р а в л е н и я в код, о н р е ш ает, ч т о эта р а б о т а для н е го п о д х о ди т. И у в ерен , ч то б ы стр о ст а н е т в это м дел е н асто яш и м п р о ф е с с и о н а л о м .
else
if
(average
<
П о м ест ив усло ви е 8 скобки, м ы у с т р а н я е м ош ибку в к а л ь к у л я т о р е IQ-
y c m j- a нен а Д обавлением °твсі^сгг>Бі|іоЩ их СКовоК.
Н о м о ж ет б ы ть, О уэн и зл и ш н е сам оуверен? Ж е л а т е л ь н о п р о т е с т и р о в а т ь и с п р ав л е н н ы й с ц е н а р и й и т о л ь к о п о то м думать об отды хе..
далее *
505
что здесь происходит?
О т ч е т не Всегда указывает на ошибку
к
со ж ал ен и ю , о тлад ка к ал ьк у л ято р а I Q ещ е н е зак о н ч е н а, п отом у ч то F irefo x с н о в а указы вает н а ош ибку, н о уж е в другом м есте. О уэн п о п ы та л ся п о л о ж и т ься н а в ы д аваем ы е б р ау зер о м о ц е н к и , н о н а э т о т р а з, каж ется, п р о сч и тал ся .
В о т скобка, парная Эля т о й , о к о т о р о й у п о м и н а е т р!гегох, ■т а к чт о со скобкам и ц данной ф у н к ц и и все 8 порядке.
<html> <head>
function ShowIQClassMata, i alert("Click Off u . document.9etEle„e„tByM("outpuj
,
“ i«OClass,data, .
Мы р а с с м а т р и в а е м одну ош ибку за один р а з, п о э т о м у данную зап ись снова п р о и гн о р и р уем .
' "Vou are CeaU„,
,4 r "
alculate the average IQ var average = ofor (var 1 . 0,- 1 < 0 a 0 average +- data
average , Math, floor tillgi ^ B o m скобка, на о т сут ст вие кот о р о й ука зы ва ет Firefox
ih
// Return the class! |AB ’ EffOfS If (average < 20) ( r— return "people „ho
Warnings
Messages
}
eise if (ave^^^^ < retijrii.>pg^le who
Error: ffiTssingIafterfafictionbofly
v
Source Flfe^ Шй:/ f /Users
\
®lse if (average < ?C J return "people who :
t'
else if (averag < 81) '• J i^eturn "people who £ else if (average < 9i) ^ return "people who c'"“
EiTon shov^^Class is not defineil
шІЛШй
^S&yrc«Fik;
else if (average < ur J return "people of av€ else if (average < 121) ™ J return "people of superio else if (average < 141, , . , "P-Ple Of very superior in^ else ( return "geniuses";
Кажется, твой магический от ладчик перестал работать. У этой функции все скобки на месте.
‘55ript>
</head>
<body onload."sho„IQClass(l„3) <-,^src=..bral„,p„g.. alt'Jb!;!:.. />
Браузеру можно верить не всегда. К ак в и д и те, со ско б кам и у ф у н кц и и все в п о р яд ке. Н е с м о т р я н а все сво и сп о со б н о сти , F irefo x в д ан н о м случае ср аб о т а л н е в е р н о . В п р о ч ем , у п о м и н ан и е об отсутствую щ ей скобке я в л я е т с я п о вод ом о б р а т и т ь п о в ы ш е н н о е в н и м ан и е н а д ан н ы й аспект.
506
о
Error Console
глава 11
l;
Une:.i
охота на ошибки
инш ерчретаахоороМ JaVa^crij=>t.
Ц|>оБе]=>ьдае скобки Б данном сЦена|зии, Чщобь1 понять, Чщо именно с ними <html> <head> <title>BSI Case 1: IQ Calculator</title>
не т а к .
<soript type="text/javascript"> var iqs = [ 113, 97, 86, 75, 92, 105, 146, 77, 64, 114, 165, 96, 97, 88, 108 ]; function showIQClass(data) ( alert("Click OK to begin IQ calculation.”); document. getElementByld ("output") .innerHTML = "You are dealing with <em>" + calclQClass(data) + "</em>.";
} function calclQClass(data) { // Calculate the average IQ var average = 0; for (var i = 0; i < data.length; i++) { average += data[i]; average = Math.floor(average / data.length); // Return the classification of the average IQ if (average < 20) { return "people who should kill their tvs"; else if (average < 50) { return "people who should really hit the books";
} else if (average < 70) { return "people who should hit the books";
) else if (averag < 81) ( return "people who should consider brain exercises";
) else if (average <91) { return "people who could be considered dull";
) else if (average < 111) { return "people of average intelligence";
} else if (average < 121) { return "people of superior intelligence";
) else if (average < 141) { return "people of very superior intelligence";
} else { return "geniuses";
</script> </head> <body onload="showIQClass(iqs);"> <img src="brain.png" alt="brain" /> <br /> <div id="output">Ready to calculate the average IQ.</div> </body> </html>
далее ►
507
стань решением
гадшщАчи ^ а М 1^ЖНо ёььЛо nj^oB ejniipb с к о б к и <html> <head> <title>BSI Case 1: IQ Calculator</title>
Б данно]уг cUeHap*uu и цонящь, Чщо именно с HuMu не т а к .
<script type="text/javascript"> var iqs = [ 113, 97, 86, 75, 92, 105, 146, 77, 64, 114, 165, 96, 97, 88, 108 ]; function showIQClass(data) { alert("Click OK to begin IQ calculation."); document.getElementByld("output").innerHTML calclQClass(data) + "</em>.";
) После в ы р а function calclQClass (data)f{% I I Calculate the averagee TQ жения var average = 0; для for (var i = 0; i < data.length; i++)(( переaverage += data[i]; МеННОМ ^^verage = Math, floor (average / data, length) ; a d d itio n Эолжна стоять eturn ..people k ^ o u i d k i l l th e ir tvs"; 3aK pt> i-(T) --
6afOU4a S ! ^ s e CKo Sk A.
"You are dealing with <em>" +
1
^^сщ ранения
оШ цбки Д обавим ........^ У .......... эт о й от кры ^ баю щ ей с к о ккы от сут ст вус^m пара!
if (average < 5 0 ) ^ 0 - __ ___________ "people who shiuld really hit th e b o o k s ^
aise if (average < 70) ----return "people who should hittte books "~r>
Q ,se if
(averag < 81)( return "people whoI sKould snou. consider brain exercises^^
©
« s e if (average < 91)Г{Л-.............. ^.^^^return "people who coHld be considered d u l l " 7 ^
Закры Б аю п^Ю ся CKo6ig.
А м о ж н о , наоборош , у б р а т ь о т к р ы ва ю щ у ю скобку п о сле цикла fo r, ведь ц и кл все равно з а п у с к а е т т о ль к о одну ст р о ч к у кода. Скобки т у т нужны т о ль к о для наглядност и.
else if (average < 111)^77 ------- ---- — -v. return "people of averse intelligence";]
Q ) ---------------------—
^
Л е е if (average < 121) f o ____ ________ — ^_jeturn "people of supeiKor intelligence";^ else if (average < 141) return "people of very superior intelligi
Q, re t W n "geniuses"
#
< /^ ril </head> <body onload="showIQClass(iqs);"> <img src="brain.png" alt="brain" /> <br /> <div id="output">Ready to calculate the average IQ.</div> </body> </html>
508
глава 11
Несовпадающие или отсутствующие скобки являются частой ошибкой в 1ауа8спр1. Но ее легко избежать, уцелив повышенное внимание синтаксису.
охота на ошибки
Неопределенные переменные К аж ется, о тд ы х О уэну н е св е ти т, потом у ч т о кал ьк ул ятор I Q о б н ар у ж и в ает все н о в ы е и н о в ы е о ш и б ки . Т е п е р ь F irefo x указы вает, ч т о п е р е м е н н а я «не о п р ед ел ен а» , ч то н а п о м и н а е т нам ф и кти вн ую ош ибку, о к о т о р о й уж е до кл ады вал I n te r n e t E x p lo re r. Н о н а э т о т р аз н е о п р е д е л е н н а я п е р е м е н н а я н а зы в а е т с я a v e r a g , а н е i q s .
О б р а т и т е вн и м а н и е, чт о вт о р а я ош ибка исчезла сам а содой. И ногда внесенные одном м е с т е и сп р авлен ия способны у с т р а н и т ь срази несколько ош ибок
воо
Возьми 6 руку карандаш Как вы думаете, что означает термин undefined в контексте последней обнаруженной Оуэном ошибки?
далее *•
509
проверь свою работу
Возьми в руку карандаш Решение
Вот что означает термин undefined в контексте последней обнаруженной Оуэном ошибки.
.*5. несозЭднной перем енной^ т а к м к п е р е м е н н о й J к о т о р о й не было присвоено начальное значение. О ш ибка во зн и ка ет п р и ссы лке на т а к у ю п е р ем ен н у ю .
иногда Все просто в д ан н о м случае о п р е д е л е н и е u n d e fin e d о т н о с и л о с ь к п ер е м е н н о й , кото р у ю п о п ы та л и с ь и сп о л ь зо в ать , н е создав, х о т я и со в ер ш ен н о случайно. П р и ч и н о й стал а о п еч атк а. В р езу л ьтате и н т е р п р е т а т о р Jav aS crip t р еш и л , ч т о п е р е д н и м совсем д ругая п ер ем ен н ая .
function
// Calculate the=
r, , ,
average - 0
^0
for (var i . o-'i < H ^ «erage ditall,;
I
''re't:"“^"'"
--age
T ' ’“ 9e < 50)
IQ
У с т р а н и т ь one чат ку прост о, а б о т оонйруж ит ь т рудно! —:
reall,
th
"people „.o 3.o„ld M t
-
--------------------------------
t.e
e lse if
}
(average < 81)
{
r eturn "people w ho s h o u l d c o n s i d e r b r a i n exercises";
if (average <
else If (average < щ ,
/
h
,
,
і,
И сп р а ви в о п е ч а т к у , мы реш им пробле м у неопределенной перем енной.
,
)
if -average <
Иногда причиной проблемы может стать обычная опечатка.
,
"
i-elllg.„,„,,.
(average < ip-i\ superior
Calculator
l^iiigence";
О
averag average Ready to calculate the average IQ. Click OK to begin IQ caiculat Done
510
глава 11
охота на ошибки Ч асзц о
^аД аБ аеМ ы е БоИ роС Ь! Есть ли разница между «undefined» и «not defined»? ; Нет. Термины означают одно и то же, просто некоторые браузеры используют один из них, а некоторые — другой. А в чем тогда разница между «undefined» и
Про значения «undefined» и null нужно помнить только то, что в логических выра жениях, например, при проверке условия
А так как этой новой переменной значение еще не присвоено, невозможно использо вать ее в условии оператора i f . Вы же не можете написать обзор фильма, даже не посмотрев его?
в операторе i f они дают значение
false. Именно поэтому код вида if (someObject) используется для про верки существования объекта перед тем, как осуществить доступ к его членам.
null?
3 » Вы шутите? Работая в текстовом редакторе, я постоянно делаю опечат ки, и это ни на что не влияет. Почему иа7а8сг1р1 столь чувствителен?
А почему опечатка сделала пере Q l Здесь все сложнее. На техниче ском уровне между «undefined» и null существует разница, но она не настолько существенна, чтобы об этом задумы ваться. Дело в том, что null — это значение, которое можно присвоить пере менной. Существует также тип данных undefined, к которому автоматически причисляются все переменные, которым пока не присвоено никакого значения. Но переменным никогда автоматически не присваивается значение null. Это делается вручную на начальном этапе, чтобы показать, что объект еще не был создан.
менную
average
неопределенной?
Как это случилось? на то что переменная 0:! Несмотря была создана и инициализи
average
рована, JavaScript не может установить связи между переменными averag и average только потому, что их имена похожи. С точки зрения JavaScript переменная averag могла называться и shazbot или lederhosen. Други ми словами, JavaScript интерпретирует ее
; к этому вам просто придется привык нуть. Сценарии пишутся не для людей, а для машин, и машины не прощают ошибок, вне зависимости от того, на каком языке написан сценарий. Он перестанет работать даже из-за одного неверного символа. Существует определенная свобода в расстановке пробелов и знаков переноса строки, но сам код не должен содержать ошибок.
как совершенно другую переменную.
Работа с цифрами П о сл е и с п р ав л е н и я о п е ч а тк и кал ьк у л ято р 1Ц н ач ал р а б о т а т ь к о р р е к т н о , вы ч и с л я я ср е д н е е и з м асси ва ч и сел и о т о б р а ж ая по резул ьтатам соответствую щую к л асси ф и к ац и ю . О уэн м о ж ет с ч и т а т ь р аботу в ы п о л н е н н о й и п о ч и т ь н а лаврах ... в о т т о л ь к о н ад олго ли.'' вы Case 1: iQ C a icu l^ r л .
О
Б лагодаря ст а р а н и я м О уэна к а л ь к у л я т о р IQ т е п е р ь р а б о т а е т maKj как и было задум ано к у , М ы y c rn j^ a H u jiu
/
_
Y o u а » dealing with p e o p le o f a v e ra g e in teU ig en ce.
Done
■_
далее ►
511
звони и выигрывай и > КЛЮЧЕВЫЕ МОМЕНТЫ
^
Хотя большинство браузеров и снабжено консолью, на которой отображается информация об ошибках иауаЗспр!, эта информация не всегда достоверна. Несмотря на излишне схематичный характер инфор мации об ошибках, она зачастую дает понять, на что именно нужно обратить особое внимание.
Распространенной ошибкой является неверная расстановка скобок вокруг блоков кода — следите, чтобы число открывающих и закрывающих скобок совпадало. Опечатку легко сделать, но трудно обнаружить — всегда проверяйте имена идентификаторов.
Звонки на радио Н е успел О уэн о б р ад о в а ть с я удачном у за в е р ш е н и ю р а б о т ы , как ему д ал и н о в о е зад ан и е. Н а э т о т р а з ему п р е д с то и т и м е т ь дело со сц е н а р и е м , обрабаты ваю ш ;им зв о н к и н а р ад и о , к о т о р ы й пс н ом ер у зв о н к а о п р е д е л я е т п о б е д и те л я в и к то р и н ы . С ц е н ар и й д о л ж ен п о д с ч и ты в а ть зв о н к и и п ри суж дать победу человеку, позво н и вш ем у , н а п р и м е р , седьм ы м .
В Ы С а $ е ? \.У п п П 9 С аН ег
© .© в
512
глава 11
охота на ошибки
Начинаем расследование П е р е д и с п ы т а н и е м с т р а н и ц ы в б р ау зер е О уэн р еш и л взглянуть н а ее код (его м о ж н о ск ач ать п о адресу http://wivw.headfirstlabs. сот/books/hfjs/), ч то б ы п о н я т ь , каким о б р азо м о н р аб о т ае т . Ведь и н о гд а м о ж н о сразу увидеть, ч т о к о н к р е т н о и д ет н е так, и л и по к р а й н е й м е р е п о н я т ь , как и м е н н о д о л ж ен р а б о т а т ь сц ен ар и й .
И м я звонящ его и н о м е р вы игравш его звонка в м е с т е с о б ъ ек т о м fo r m п ер ед а ю т ся в ка ч ест ве а р гу м е н т а ф ункции ckeckW innerQ .
Если ном ер звонка с о в п а д а ет с вы >игрышныМ1 показы ваем им я звонящ его
С чет чи ку з в о н ков п р и с в а и в а ет с я начальное значение ноль.
от дельном кне.
Увеличение показаний счет чика на единицу.
Если звонящ ий не я вля ет ся по б ед и т е л е м , уд а ля ем его и м я из поля.
Сценарий с е р в е р а для с о хр а н е^ ч я инф о р м а ц и и ' победит еле.
Щ елчок на кнопке Call вы зы вает ф ун к ц и ю про вер ки поб едит еля ckeckW innerQ .
Возьми в руку карандаш
Помогите Оуэну, указав, сколько ошибок, по вашему мнению, содержит данный сценарий.
Ноль Одна
Четыре
две
Три
Пять
далее ►
513
что? синтаксическая ош ибка
Возьми в руку карандаш IX
'ешение
Ноль Одна
Вот сколько ошибок содержит код данного сценария.
две
Трц
Пять /Д авайт е продолж им и п о м ож ем О уэн у н а й т и все эт и ошидки...
Проверка синтаксиса (ошибка # 1 ) П олучи в п р е д с та в л е н и е о то м , как до л ж ен р а б о т ат ь э т о т сц е н а р и й , п о с м о тр и м , ч то п р о и с х о д и т п р и п о п ы тк е зап усти ть его в б р ау зер е F irefox. Э то т б р ау зер н ем ед л ен н о д ае т свед ен и я о си н та к си ч е с к и х о ш ибках, т о есть о н ар у ш ен и ях п р а в и л я зы к а JavaS crip t.
Браузеры всегда сообщают о синтаксических ошибках.
О
пшаЬвг ФcaiiHm 4. else i »ost caller
Б р а узер у к а зы в а ем. на п р о ц ед ур у соединения ст р о к.
)
caiierPield.select();
П р и в к л ю ч е н н о й ф у н кц и и со о б щ е н и я об о ш и б ках б р ау зер ы всегда и н ф о р м и р у ю т о п р о б л ем ах с си н так си сом . И м е н н о это посл у ж и т о т п р а в н о й т о ч к о й д ля н аш и х и зы ск ан и й .
514
глава 11
■LoUay s w-sner: }
охота на ошибки
Аккуратнее со строками F irefo x указал н а проц едуру с о е д и н е н и я стр о к , и и м е н н о ее мы н ач н ем а н а л и зи р о в а ть. В ы зы в ается ф у н кц и я a l e r t ( ) , в к о т о р о й н еск о льк о ст р о к о в ы х л и т е р а л о в с о е д и н я ю т ся с п е р е м е н н ы м и c a l l e r и c a llN u m . if
(callNum
=
alert(caller
winningNum) +
+
callNum
+
Э т и два ст р о ко вы х л и т е р а л а о о ьединяю т ся с двум я п ер ем ен н ы м и .
В J a v a S c г ip t в а ж н а п а р н о с т ь к а в ы ч е к . К ав ы ч к и всегда д о л ж н ы и д ти п ар ам и , и н ач е Jav aS crip t н е см о ж е т о п р е д е л и т ь , где к о н ч ае т ся од н а с т р о к а и н ач и н а е т с я другая. В с ц е н а р и и , об р аб аты ваю щ ем зв о н к и н а рад и о , в од н ом и з ст р о к о в ы х л и т е р а л о в н е х в а т ает кавы ч ек. Т о е с ть п е р ед нам и б ан ал ь н ая с и н так си ч е ск ая ош ибка. И д о с т а т о ч н о д о б ав и т ь н ед о стаю щ и е к авы ч к и в к о н е ц строки :
if
(callNum
=
alert(caller
if
(callNum
=
al e r t (caller
winningNum) +
",
caller
numbei^^^
callNum
+
"...
today's
winner!")
winningNum) +
",
caller
number
" -I- c a l l N u m
+
"...
today's
winner!")
Q m u S x a усгв|=>анена ДоёаБл^ением naj^H bix КаВьхЧек.
далее ►
515
важно быть последовательным
КаВычки U апострофы Н е д о стаю щ и е к ав ы ч к и — эт о т о л ь к о о д и н в а р и а н т ош и б ки , в о з м о ж н ы й п р и р а б о т е со стр о кам и . Д ел о в то м , ч т о вы д ел ен и е с т р о к в Jav aS crip t и в ы д ел е н и е атр и б у то в в Н Т М Ь во зм о ж н о как п р и п о м ощ и кав ы ч ек, т а к и п р и п о м о щ и а п о с т р о ф о в . А зн ач и т , важ н о не п ер еп у тать эт и д ва знака. А т р и б у т ы HTML “заклн?чян?тся в кавш ки. <input type="button" value="Call"<
onclick="checkwinner(this.form, document.getElementByld{'caller')-value, 7)" />
V Ч а с т о д ля в ы д ел е н и я Н Т М Ь -атр и б у то в и сп ользую т кавы ч ки , в то в р е м я как с т р о к и Jav aS crip t, р а с п о л о ж е н н ы е вн утри эти х атр и б у то в, в ы д ел яю тся а п о с т р о ф а м и . Н о м ож н о и с п о л ь зо в ат ь и о б р а т н ы й сп о со б в ы д ел ен и я , как п о к а за н о ниж е: <input type='button' value='Call'
—
С т роки J a v a S c r ip t в н у выдр.л/>и1т р и аат тю р иибцт б у т а выделены п р и п о м о щ и апост роф ов.
С оврем енны е с т а н д а р т ы XHTML не р а зр е ш а ю т вы делят ь а т р и б ут ы ( ап о ст р о ф а м и . Д)
I
onclick='checkwinner(this.form, document.getElementByld("caller") .value, 7)' />
4 8 эт ом прим ере anocm po_ ф ы и с п о л ь зу ю т с я для H T M L --------- — ат р и б ут о в,, в т о вр е м я как с т р о к а J a v a S c r ip t заклю чена в кавычки. В аж н о за р а н е е р еш и ть , ч т о и м е н н о вы будете и с п о л ь зо в ат ь для в ы д ел ен и я о п р е д е л ен н ы х ф р а гм е н т о в кода. И т а к как X H T M L , с о в р е м е н н а я в е р с и я H T M L , т р еб у ет в ы д ел ен и я атр и б у то в т о л ь к о п р и п о м о щ и кав ы ч ек, зн а ч и т , д ля вы д ел ен и я ст р о к Jav aS crip t о стаю тся а п о с т р о ф ы . П р о б л е м а в о зн и к а е т, есл и вам тр еб у ю тся к авы ч к и и л и а п о с т р о ф , н о э т о т зн а к уже исп о льзу ется, н а п р и м е р , как п о к азан о ни ж е:
alert{'It's so exciting!'
В у д е т ли р а б о т а т ь э т о т код?
516
глава 11
В строках 1ауа8спр1 и атрибутах НТМЬ кавьпки и апострофы могут заменять друг друга. Ш ТУРМ
Что делать, если вам нужно вос пользоваться знаком, применяе мым для выделения строки?
охота на ошибки
Е$С-СимвоАЫ Р а с п р о с т р а н е н н о й о ш и б к о й я в л я е т с я и с п о л ь зо в ан и е к а в ы ч ек и л и ап о с т р о ф о в как си м в о л о в в с о став е стр о к и . И м е н н о т а к а я с и н так си ч ес к ая о ш и б ка с о д ер ж и тся в коде д ля всп л ы ваю щ его окн а. И н т е р п р е т а т о р Jav aS crip t н е м о ж ет р а с п о зн ат ь , к ак и е а п о с т р о ф ы у казы ваю т н а к о н ец с т р о к и , а как и е —яв л я ю т ся ее частью . К счастью , м ы м ож ем л егк о о б о зн а ч и т ь «реальность» сим вола, п о м ести в п е р е д ни м об ратную косую черту ( \ ) . В р езу л ьтате о н п р е в р а т и т с я в т а к н а зы в а ем ы й е8с-си м вол . alert('It\'s so exciting!');
Т е п е р ь Jav aS crip t т о ч н о зн а е т , ч т о м ы х о т е л и п о м ес т и т ь в строку си м вол а п о с т р о ф а , а н е указать н а к о н е ц э т о й с т р о к и . В п роч ем , м ы м о гл и и обм ан уть и н т е р п р е т а т о р , за м е н и в о гр ан и ч и в аю щ и е строку зн ак и н а кавы чки . alert("It's so exciting!
_ Esc -с и м в о л больш е не нужен.
Esc-символы указывают на символьные литералы в строках.
В п ро ч ем , м о ж н о при дум ать и в о т т а к о й в а р и а н т кода: alert("They said, "you've won!"");
Т ак к ак в дан н о м случае с т р о к а с о д е р ж и т в ка ч е ств е л и т е р а л о в и кав ы ч ки , и а п о с т р о ф , о с т ае т с я т о л ь к о п р и б егн у ть к п о м о щ и escсим во л о в. Т а к о й с ц е н а р и й к том у ж е н ам н о го б езо п ас н е й , потом у ч то н е д опускает н и к а к и х вари ан тов^гр а к т о в ^ . ддбол туил alert("They said, \"you\'ve won !\"
о б я з а т е л е н , НО
Аучш е его п о с т а вить).
пражнение
Устраните проблему, связанную с наличием кавы чек и апостроф ов, в показанном ниже фрагменте кода.
var message = 'Hey, she's the winner!';
var response = "She said, ''I can't believe I won.""
<input type="button"' vaiue=="Winner" onclick="givePrize("Ruby");" />
далее >
517
реш ение упражнения
Вот каким образом при помощи esc-символов были внесены исправления в код, содержа)З Ж Н 2 Н И 2 'ешение
множество апостроф ов и кавычек. var
message
=
' Hey,
she's
the
winner!';
v a r m essage = 'H ey, s h e \ s th e w inner!'; Здесь e sc си м во л не о б яза т елен, т а к как апост роф находит ся в ст роке, за клю ченно й в кавычки.
var
response
=
"She
said,
"I
can't
believe
1 won.""
~ — v'ar response - "She sa id , V I c a n \‘t believe I w o n.\"" <input
type="button"
value="Winner"
o n c l i c k = " g i v e P r i z e (" R u b y " ) ;"
/>
^ “^ in p u t t y £ e ~ ‘b u tto n " v a lu e -'W in n e r" o n c lic k - ‘givePrize('Ruhy');" /> ................................................................................................: ...................................... 8 даннолА случае e sc -с и м во лы р а б о т а т ь не б уд ут , т а к как у нас и м е е т с я с т р о ка J a v a S c r ip t вну т р и H TM L-а т р и б ц т а . П роблема р еш а ет ся п р а вильной расст анобкой кавы чек и ап ост роф ов.
Неопределенность функции (Ошибка # 2 ) И так, од н а о ш и б ка и сп р ав л ен а, по О уэн зн ает, ч то р а б о т а дал ека о т зав ер ш ен и я . Р аб о та о б р а б аты ваю щ его зв о н к и с ц е н а р и я н а ч и н а е т с я гладко, б ез ош иб ок, а вот п р и щ елчке н а кн о п к е Call п р и п о п ы тк е указать им я зв о н ящ его п о л ьзо в ател ь с тал к и в ается с п р о б л ем о й . И каж ется, о н а связан а с ф у н кц и ей c h e c k w i n n e r {). СЭ
BSI Case 2: Winning Caller
e o e
S J -
CaEer n a m e : jH ow ard
0 0 6 в ' 1 All
Щ елчок на к н о п ке Call п р и во д и т к ош ибке, к а к и м т о образом с в я занной с ф ункцией checkW innerQ .
& Errors
Error Console iL Warnings
m Messages
Clear
Ermr. checto«Rn€f Is not defined Source
П очему - m o э т а ф ункция не о п р е д е лена.
518
глава 11
f&t’N /Users /mjchaei .‘Document«/headWr’
§iЬMШШйЩfш\ммШçм^2^2^hmï Une 1 — - ...........- .......... У казание на н о м е р ст р о ки н а м ничем не пом ож ет , т о ч н о зн а е м , чт о с п ер во й ст р о ч ко й H T M L кода п р о б ле м нет .
охота на ошибки
Обычный список подозреваемых О уэн р е ш а е т и с п о л ь зо в ат ь п о л у ч ен н ы й р а н е е о п ы т и п р о й ти с ь по списку сам ы х р а с п р о с т р а н е н н ы х в Jav aS crip t ош и б ок. Ведь, во зм о ж н о , с т а к о й о ш и б ко й о н уже сталкивался.
,rm, caller, winningNum) звонка на единицу
кругла, cKosJ .. Несовпадающая им, отсу^
(
// проверка победителя callNum + form, submit о ;
else
" ^"“irertirw ПГсГеп"^детеш1 irilS fe fa ^ a lu e = "Next caller..
' caller’, ;
callerField.focusO ; c a l l e r F ield.select 0 ;
Ссылка на ф ун к ц и ю ckeckW in n erQ попадаем ся т о ль к о два раза.
</script </head>
</form> </body> </html>
возьми в руку карандаш Укажите, какая проблема, с вашей точки зрения, мешает рабо те сценария обработки звонков.
I I Н есо в п ад аю щ ая и л и отсутствую щ ая ф и гу р н ая скобка.,
I I О п е ч а тк а в и м е н и и д е н т и ф и к а т о р а .
□
Н есо вп ад аю щ ая и л и отсутствую щ ая круглая скобка. Н е п р а в и л ь н о е и с п о л ьзо в ан и е к ав ы ч ек и ап о ст р о ф о в .
П К акая-то другая п роб л ем а.
далее >
519
реш ение упражнения
Возьми В руку карандаш, Решение □
Вот в чем заклю чается проблем а, м еш аю щ ая работе сцен ари я о б р а б о тк и звонков.
Н есо в п ад аю щ ая и л и отсутствую щ ая ф и гу р н ая скобка.
_ Н есо в п ад аю щ ая и л и отсутствую щ ая круглая скобка. Н е п р а в и л ь н о е и с п о л ьзо в ан и е к ав ы ч ек и ап о с т р о ф о в .
О п е ч а тк а в и м е н и и д е н т и ф и к ат о р а . □
К акая-то д ругая п роб л ем а.
ф ункция ckeckW in n erQ вы зы вает ся как ck e c kw in n erQ j п о т о м у ч т о в и м ен и по ош ибке по яви ла сь м а ле н ьк а я w. В р е з у л ь т а т е и н т е р п р е т а т о р п ы т а е т с я вы зв а т ь ф у н к ц и ю , ко т о р а я не была о п р е д е лена.
А л я ус т р а н е н и я ош ибки дост ат очно за м е н и т ь w на W
t y p e="butt||fi"
# 2 y c n f -а н е т
UC-
^аВ лет ем
Ш ет ф у н к ц и и .
J <input
Г
value="Call'
onclick="checkWinner(this.form, document.getElementById('caller').value, 7)" />
Побе}кдают бее (Ошибка # 3 ) Д аж е п о сл е у с т р ан е н и я д о сад н о й о п е ч а т к и в и м ен и ф ун кц и и с ц е н а р и й н е р а б о т а е т нуж ны м о б р азо м . Х о р о ш о х о т я бы то, ч т о б р ау зер н е в ы б р ас ы в а е т с о о б щ е н и й об ош ибках. В от т о л ь к о в ы и гр ы ш н ы м т е п е р ь я в л я е т с я каж ды й зв о н о к —с ц е н а р и й п р и эт о м п р и с в а и в а е т ему к о р р е к т н ы й н о м ер . И ес л и О уэн н е спа сет ситуацию , р а д и о с та н ц и я р а з о р и т с я н а вы д ач е п ри зов!
BSie. caller nymber 7...today’s w in ie
С
Ж
Э
С т ш н н о т о , ч т о каж до м у звон ку п р и сва и ва ет ся вы игры ш ны й н о м ер , вне за ви си м о ст и о т т о го к а к и м по сч е т у он я вля ет ся С£^МОМ дбЛ&.
|
"“« b er ^...today's win, e
tobv. сан« number
П обедит елем о б ъявляет
СЯ каждый позвонивший.
520
глава ft
охота на ошибки
Отладка с помощью ВсплыВающих окон М ы зн аем , ч т о о п р е д е л е н и е п о б е д и те л я п р о и зв о д и тс я путем с р а в н е н и я п е р е м е н н о й c a llN u m с аргу м ен то м w in n in g N u m ф у н кц и и c h e c k w i n n e r ( ) . Н о что-то с эти м кодом н е так, по это м у д ав а й те б о л ее п о д р о б н о р а ссм о тр и м , ч то п р о и с х о д и т с п е р е м е н н о й c a llN u m . На первы й взгляд с к о ~ -------- - дом все в порядке. if
(callNum
=
winningNum)
-
И м е е т см ы сл п р о с ле д и т ь , как м е н я е т с я значение п е р ем е н н о й саНМит по м е р е раб от ы сценария.
Как бы посмотреть на зна чения переменной в раз ные моменты времени?
Всплывающие окна являются отличным инструментом р я отслеживания значений переменой.
В с п л ы в а ю щ и е окна как инструмент отладки.
В спл ы ваю щ и е о к н а го д я тся н е т о л ь к о для о т о б р а ж ен и я и н ф о р м а ц и и , п р е д н а зн а ч е н н о й д ля к о н е ч н ы х п о л ьзо ва т е л е й . С и х пом ощ ью м о ж н о так ж е о т сл еж и в ат ь зн а ч е н и я п е р е м е н н ы х и п р о в е р я т ь к о р р е к т н о с т ь в ы зо в а о тд ел ьн ы х ф р а гм е н т о в кода. В наш ем случае п р и п ом ощ и всп л ы ваю щ их о к о н м ы п р о сл ед и м за зн а ч е н и я м и п е р е м е н н о й c a llN u m . В сплы ваю щ ее окно по зв о л я е т п р о след и т ь за зн ачен ием п ер ем енной callNum .
f~ o iT 3
далее >
521
всплывающие окна — это тоже инструмент
Следим за значением переменной Т е р м и н «контрольное значение» о зн а ч а е т н е п р е р ы в н о е о т с л е ж и в а н и е п е р е м е н н о й в п р о ц е сс е р а б о т ы п р о гр ам м ы . В сплы ваю щ ее о кн о н е п о зв о л я е т н е п р е р ы в н о сл ед и ть за п е р е м е н н о й , н о в наш ем случае о н о в п о л н е м о ж ет пом оч ь.
----------------- ' alert (callNxjm) ; if (callNum = winningNum) ( a l e r t (caller + ” , caller number
callNum + "... todayX's
winner!");
NaN
aiiVimi1".(W
О уэн п о н ял , ч т о с т о ч к и зр е н и я с ц е н а р и я п е р е м е н н ы е callNum и w inningNum р а в н ы н е с м о т р я н а то , ч т о сразу п е р ед о п е р а т о р о м if п е р е м е н н ая callNum и м е е т зн а ч е н и е NaN. У ж е од н о эт о н е совсем п о н я т н о , н о О уэн р е ш и л с н ач ал а п о с м о т р еть , ч то п р о и с х о д и т вн у тр и о п е р а т о р а i f. if (callNum - WinningNum)
(
alert(callNum); alert(caller + ", caller number Winner!"); form.submit ();
С разу после п р о вер ки усло ви я п ер ем ен н а я callN u m п о л у ч а е т значение 7.
Ш ТУРМ Теперь, когда вы знаете, что переменная callNum всего за одну строчку таинственным образом по лучила значение 7, как вы думаете, что стало при чиной этого?
522
глава 11
>^е.кущего звонка.
OiC
охота на ошибки
a v / ^ А
д к А
П Р И
п о м е а д и
И нтервью н ед ел и :
В спл ы в аю щ ее о кн о п р е з и р а е т д еф екты Head First: Д о л ж ен п р и зн а т ь с я , я слы ш ал о вас р а зн о е . Л ю ди го в о р я т, ч т о ч ас т о вы и х р а зд р а ж аете. Н о п р и это м вы я в л я е т е с ь лучш им другом о тлад чи ко в. Р асскаж и те, кем ж е вы я в л я е т е с ь на сам ом деле.
Всплывающее окно: Д о л ж н о п р и зн а т ь с я , ч т о не так-то п р о с т о р а б о тать, если п е р е м е н н а я м ен я е т ся м н ого р а з, н а п р и м е р , в п р о ц е сс е в ы п о л н ен и я ци кла.
Всплывающее окно: Э ти п е р в ы е п р о с т о н е н о р м альн ы е. М не даю т и н ф о р м а ц и ю , а я ее о т о б р а ж аю . К ак о й о т эт о го вред?
Всплывающее окно: К ак вы п о м н и те, я в сп л ы ваю и уб р ать м ен я м ож н о т о л ь к о щ елчком . А если я вспл ы ваю м н ого раз, нуж на ц ел ая с е р и я щ ел ч ков.
Head First: Н о вы «всплы ваете». Т о ч н о т а к ж е, как м н о го ч и с л е н н а я н ад о ед л и в ая реклам а. Всплывающее окно: Т о есть, если п л о т н и к не ум еет о б р ащ ать ся с м о л о тк о м , в и н о в а т м олоток? Head First: Вы х о т и т е сказать, ч то вас использу ю т некорректно? Всплывающее окно: И м е н н о так. Е сли м ен я за ставл яю т о т о б р а ж а т ь всю эту глупую реклам у, м не это н е н р а в и тс я . Н о в ы б о р а у м ен я нет. В п р о ч ем , я думал, вы х о т и т е узнать, как и м е н н о я пом огаю п роц ессу отладки . Head First: Д а, и зв и н и т е . Т а к как ж е вы эт о де лаете?
Всплывающее окно: О ч е н ь п р о сто . С каж ем , п е р е м е н н о й н е ч а я н н о п р и с в аи в а ю т какое-то н е им ею щ ее см ы сла зн а ч е н и е . П р о гр ам м и сту нуж но о тсл ед и ть, как о н а м е н я е тс я п о м ер е р а б о т ы с ц ен а р и я . И о н п р о с и т м е н я о т о б р а ж а т ь ее зн а ч е н и я. Head First: Н о каким ж е о б р азо м вы ум удряетесь узнать зн а ч е н и е п е р е м е н н о й в р а зн ы е м о м ен ты врем ен и ? Н а в е р н о е , это слож но...
Head First: П оч ем у же?
Head First: Тут вы п р авы . Н о ещ е я слы ш ал, ч то вы м о ж ете б ы ть п о л е зн ы даж е в случаях, когд а не тр еб у ется о т с л е ж и в ат ь дан н ы е. Всплывающее окно: О , да. Сущ ествую т ситуа ц и и , когд а н ея с н о , в как о й м о м ен т в ы зы вается ф р а гм е н т код а и в ы зы в ае тся л и вообщ е. И м е н н о м оя п о м о щ ь п о зв о л я е т узн ать о том , ч т о в ы зо в код а все-таки п р о ш ел успеш но. Head First: И во в сех эт и х п ро ц ед у р ах отл ад к и вы то л ь к о в р е м е н н ы й участник? Всплывающее окно: И м ен н о так. Н о я н е в о з р аж аю . В к о н ц е ко н ц о в, у м ен я есть п о с т о я н н а я р аб о та , а п ом ощ ь в отлад ке эт о так, н еб ол ьш ая п о д раб отка. Head First: С п аси б о за п о т р а ч е н н о е н а нас в р е м я и за о б ъ я с н е н и е в аш ей р о л и в д ел е б о р ь б ы с д еф е к т а м и кода. Н ад ею сь, м ы ещ е н е р а з в с т р ет и м с я .
Thanks. See уа!
Всплывающее окно: В овсе н ет. Д о с та т о ч н о в ы звать м ен я в нуж ны х то ч к а х с ц е н а р и я. Head First: П о н и м аю . А стал к и в ал и сь ли вы с п р о б лем ам и в п р о ц е сс е т а к о й работы ?
далее ►
523
это логично?
Некорректная логика О уэн н ато л кн у л ся н а ло ги ч еску ю ош ибку. Т о е сть код с о в е р ш ен н о к о р р е к т е н с т о ч к и зр е н и я я зы к а Jav aS crip t, н о д ел ает совсем н е то , ч т о д о л ж ен д елать. В д ан н о м случае вм есто == введ ен о =, и в р езу л ьтате в м есто с р а в н е н и я двух п е р е м е н н ы х п е р е м е н н о й c a llN u m п р и с в аи в а е тс я зн а ч е н и е п е р е м е н н о й w in n in g N u m .
С виду коррект ны й код на сам ом деле несет о себе т рудно обнару ж иваемую ошибку.
______ у» if
{callNum(^winningNum)
{
З ам е н и в = н а = = if
(callNum ==
winningNum)
{
Мы изёавим ат ощ ’ ош ибки # ^ .
Т а к и е о ш и б ки н е о б н ар у ж и ваю тся б р ау зер ам и . И н т е р п р е т а т о р Jav aS crip t в ы п о л н я е т свою работу, возвраш ,ая п р и с в о ен н о е п е р е м е н н о й w in n in g N u m зн а ч е н и е , к о т о р о е затем а в т о м а т и ч еск и п р е о б р азу ется в зн а ч е н и е t r u e п р и п р о в е р к е усл ови я о п е р а т о р о м i f . Д ру ги м и сл овам и, код н а п и с а н к о р р е к т н о , п р о с т о о н д ел ает н е то, ч т о нам нуж но.
( То есть логические ^ ошибки не распознаются V
браузерами?
]
у
Логические ошибки — это как полет ниже уровня радара. О с н о в н ая п р о б л ем а в то м , ч т о л о ги ч ес к и е ош и б к и в о т л и ч и е о т о стал ь н ы х н е о б н аруж и ваю тся авто м ати ч еск и . П усть сооб щ е н и я о т б р ау зер а и вы гл яд я т пугаю щ е, п о к р а й н е й м ер е, о н и даю т п р е д с та в л ен и е о том , где и ск ать ош ибку. А в о т с л о ги ч ес к и м и о ш и б кам и вам п р и х о д и тс я б о р о т ь с я уж е б ез под сказок. С д ругой ст о р о н ы , т а к и е о ш и б ки п р и в о д я т к н е к о р р е к т н о й р а б о т е с ц ен ар и я . Н а п р и м е р , есл и п р и ч и н о й стал а н е и н и ц и а л и зи р о в а н н а я п ер е м е н н а я , с о о б щ ен и е « u n d e fin ed » п о к аж ет, ч то и м е е т м есто п о п ы тк а со сл аться н а такую п ерем енн ую . Т ак ч то в о х о т е н а л о ги ч ес к и е о ш и б ки так ж е ес ть свои т о н к о с т и и х и т р о с ти .
524
глава 11
охота на ошибки
КЛЮЧЕВЫЕ МОМЕНТЫ Синтаксическими называют ошибки, нарушающие правила языка иауаЗопр!. Они обнаружи ваются браузером.
В НТМ1-атрибутах обработчи ков событий, содержащих код иауаЗспр!, нужно использовать как кавычки, так и апострофы.
Количество открывающих и за крывающих апострофов и кавы чек должно совпадать.
Всплывающие окна можно ис пользовать для отслеживания значения переменных.
В операторе проверки условия часто используют = вместо ==, что становится причиной ошибки.
часш° задаваем ы е БоЦ роС Ь! В роли esc-символов могут выступать только кавычки и апострофы? ; Нет, в JavaScript поддерживаются и другие esc-символы. Например, вот так
\t в строку вставляется табуляция.
Знак переноса строки представлен символом
\ п . А так записывается обратная косая черта \ \ .
и ничего больше. KaKoif бы символ вы ни применяли для обозначения начала
при ссылке на неопределенную переменную или функцию?
из JavaScript как значение атрибута. Вы можете вставлять эти символы
0 ; Неопределенной называется переменная, которая или не была создана, или же ей забыли присвоить начальное значение. В обоих случаях ее значение воспринимается как
в HTIVIL-атрибуты при условии, что они не конфликтуют с символами, указывающими на границы атрибута. Ведь значения атрибутов обработчиков событий не интерпретируются, как код JavaScript.
Эти символы часто применяются для форматирования текста во всплывающих окнах. Символы \
t и \п выравнивают
текст и разбивают его на строки. 3 * Почему ограничено использование esc-символов в HTML-атрибутах? Q ; Дело в том, что HTML-атрибуты не подчиняются правилам JavaScript в том, что касается символов, ограничивающих значение. Вы можете использовать escсимволы в строках JavaScript, входящих в HTML-атрибут, но те же самые символы при этом могут применяться для обозначения границ атрибута. С точки зрения HTML атрибут — это значение, которое появляется между кавычками или апострофами.
Что именно происходит
атрибута, следующий аналогичный символ будет указывать на его конец. Ведь HTIV1L не обрабатывает esc-символы
неопределенное. Поэтому попытки прочитать его и проделать с ним какие-то операции не имеют смьюла, и JavaScript создает сообщение об ошибке. Аналогичная ситуация возникает, если при вызове функции интерпретатор JavaScript не может ее обнаружить. Вызов неопределенной функции не имеет смысла, и вы снова получаете сообщение об ошибке.
Существуют ли отладчики иауа8сг1р1, предоставляющие подробный контроль процесса
получала значение
отладки?
проверкой условия в операторе
; Да, такие отладчики бывают. И наверное, вам имеет смысл попробовать их в деле. Однако хорошая манера написания кода вкупе с изученными в этой главе методиками отладки способна помочь вам в создании
Почему переменная callNum
NaN перед 1 f?
! Мы этого не знаем. Можно только сказать, что с кодом все еще что-то не в порядке. А значит, нужно продолжать отладку...
сценариев, не содержащих ошибок.
далее >
525
синтаксическая ошибка и логическая
Беседа у камина Синтаксическая и логическая ошибки обожают плохие сценарии.
Синтаксическая ошибка:
Логическая ошибка;
Э й, я т е б я знаю . Н асл ы ш ан а о тв о ем к о в а р стве. Н о л ю б и ш ь л и т ы п л о х о н а п и с а н н ы е с ц е н а р и и так ж е, как лю блю и х я? О да! Н е т н и ч е го лучш е с ц е н а р и я , к о т о р ы й н а п е р в ы й взгляд в ы гл яд и т к о р р е к т н о , н о н а сам ом дел е п е р е п о л н ен ош ибкам и. Н е т , н ет. Я п р е д п о ч и т а ю с ц е н а р и и , п р о б лем н ы е даж е с виду. Я там вы деляю сь. М ои с е с тр ы р а зб р о с а н ы п о всем у сц ен ар и ю , и б р ау зер г а р а н т и р о в а н н о будет возмуш;ен.
Н е м огу н е о ц е н и т ь тв о е х и тр о у м и е, н о ведь т ы допускаеш ь р аб о ту сц е н а р и я . А я н а это п о й т и н е могу. С ц е н а р и й в о о б щ е н е д о л ж ен р а б о та ть . Н и как.
Э то да. Н о к со ж ал ен и ю , п р и ч и н я е м ы й нам и в р ед весьм а о гр а н и ч е н . П о р т и т ь веб с т р ан и ц ы , не д авая им к о р р е к т н о р а б о т а т ь в есело , н о б ольш е никуда у нас доступа нет. В от есл и бы нас пустили п а ж е с т к и й диск, п о л н ы й в аж н о й и н ф о р м а ц и и !
И ч т о тут веселого? Все зн аю т, ч т о удары и сп о д ти ш ка б о л ее эф ф е к т и в н ы . П усть п о л ьзо в ат ел ь думает, ч т о все в п о р я д к е, в то в р е м я как т о там , то зд есь н ачнут в о зн и к а ть н еб о л ьш и е п р о б л ем ы . И есл и как следует п о ст ар ат ься , п о л ь зо в а т ел ь вооб щ е задум ается о том , р а б о т а е т л и его браузер.
А ведь эт о м ы сль. Ж а л ь , ч т о я сам а п е до думалась о с тан ав л и в ать раб о ту с ц е н а р и я так ж е, как и ты . И л и даж е вы зы в ать п ад ен и е б раузера. В от б ы ло бы здорово!
Д а, эт о б ы ло б ы п о тр ясаю щ е. А ты уверен а, ч т о н ам н и к а к н е л ьзя туда п рон икн уть?
526
глава 11
охота на ошибки
Синтаксическая ошибка; У вы , и н т е р п р е т а т о р Jav aS crip t д е р ж и т нас креп ко .
Логическая ошибка; Н и ч его . В есел и ться это нам н е меш ает. Я р асск азы в ал а теб е п р о м ал ен ьки й ф окус с о п е р а т о р а м и = и ==?
Н ет. А как он рабо тает? П р о гр а м м и с т х о ч е т н а п и с ать == и с р ав н и т ь д ва зн а ч е н и я , н о случайн о вво д и т = и вм есто эт о го в ы п о л н я е т п р и с в аи в а н и е. А по то м си д и т часам и, п ы та я сь о т ы ск а ть к о р е н ь зла. И д аж е и н т е р п р е т а т о р Jav aS crip t н е м о ж ет ему п о м о ч ь, потом у ч то т е х н и ч е с к и код со в е р ш ен н о к о р р е к те н . И как т ы вы х о д и ш ь сухой и з воды? У м е н я м н ого сп особ ов. Э то т ак зд о р о в о , не наруш ая закон а, п р и ч и н я т ь массу н е п р и я т н о стей . У м ен я в ар с е н а л е т о ж е е с ть п о д о б н ы е т р ю ки. С каж ем , когд а п р о гр а м м и с т за б ы в ае т п о ст ав и ть в к о н ц е о п е р а т о р а то чку с за п я т о й . Э то н е к р и т и ч н о для и н т е р п р е т а т о р а , и все р а б о т а е т , п о к а каж ды й о п е р а т о р н ах о д и тся н а с в о е й стр о к е . Н о в о т п о п ы тк и « о п ти м и зи р о в ать» код и со е д и н и т ь о п е р а т о р ы в одну стро чк у п о зв о л я ю т м н е как следует п о в е с е литься!
Т ы н а п о м н и л а м н е одну и з м ои х л ю б и м ы х ш уток. О б ож аю , когд а п р о гр а м м и ст р е ш ае т п о м е н я т ь аргум ен ты уж е н а п и с а н н о й ф унк ц и и . П р и это м о н ч асто заб ы вает о б н о в и т ь все в ы зо в ы э т о й ф ун кц и и . И н т е р п р е т а т о р н и ч е г о н е зам еч ает, и п р о гр а м м и ст получает н ео ж и д а н н ы е резу л ьтаты из-за н е в е р н о го сп и ск а аргум ентов.
Н о есл и и н т е р п р е т а т о р вдруг ч то-то зам е ч ает, в р або ту вклю чаю сь я и о ш елом ляю со о б ш ен и ем об ош иб ке. Э й, а ведь нам и м еет см ы сл р а б о т а т ь в ком анде. Т ак м ы см ож ем п р и ч и н и т ь н ам н о го б ольш е вреда. С огласна! Д авай т а к и сделаем . Я следую за тобой !
далее >
527
ош ибочное радио
Проигрывают 8се! (Ошибка # 4 ) О уэн н а ч и н а е т п о н и м ать , ч то р а б о т а о тл ад ч и к а дал ек о н е т ак п р о ста, к ак ему сн ач ал а п о к азало сь. И с п р а в и в л оги ч ескую ош ибку в о п е р а т о р е , о н о б н аруж и л, ч т о т е п е р ь с ц е н а р и й во о б щ е н е о б ъ я в л я е т п о б ед и те л я. Е сли р ан ь ш е у нас в ы и гр ы в а л каж ды й п о зв о н и в ш и й , т о т е п е р ь все п р о и гр ы в а ю т. Э то м о ж ет н е га т и в н о п о в л и я т ь н а сам ооц ен к у слуш ателей, п о это м у ош ибку следует у стр ан и ть как м о ж н о ско р ее. в ае..
528
81 Casвг Wtn
глава 11
Звонок 3.
охота на ошибки
А така Всплывающих окон О уэн п ы т а е тс я п р о с л е д и т ь за зн а ч е н и е м п е р е м е н н о й c a llN u m . О н п о п ы та л с я в с тав и ть н е с к о л ьк о в сп л ы ваю щ и х о к о н в р а зн ы е ч ас т и кода, в р езу л ьтате о казал ся за в а л е н о кн ам и с п р а к ти ч е с к и б есп о л езн о й и н ф о р м а ц и е й . И т е п е р ь о н п р о с т о н е зн ает, ч т о п р е д п р и н я т ь дальш е...
При наличии по вт о р я ю щ его ся кода п о п ы т к и от слеж иват ь значение п ер ем ен н о й пр и п о м о щ и всплы ваю щ его окна п р и водят к п о я вле н и ю больш ого числа окон.
^
По м е р е у в е л и ч е ния числа звонящ их, п ер ем ен н а я callN um дем онст риру c m п о лн ы й с п е к т р ст р а н н ы х значений.
Было бы здорово, если бы следить за переменными можно было без всплывающих окон...
\
У
далее >
529
нет ли для этого консоли?
Отладочная консоль браузера Б о л ьш и н ств о б р ау зер о в и м ею т отлад очн ую ко н со ль, н а к о т о р о й о т о б р а ж а е т с я и н ф о р м а ц и я о содерж аш ;ихся в с ц е н а р и и ош ибках. Э то т и н стру м ен т п о зв о л я е т п о н я т ь , ч то и м е н н о н е т а к с ваш и м сц ен ар и ем . К ак вы уже убедились, лучш е всего и с п о л ь зо в ат ь к о н со л ь б р ау зер а F irefox.
SyntijiErf®'СаіїЧем! д.-»'
tsij
ass
1«
Консоль ошибок прекрасно указы ваем на о ш й к ^ щ Т н а cm i ^
^^^^^^aкcuчe-~
Мы п о ла га е м ся на
консоль ошибок браузера Firefox.
А как консоль ошибок поможет мне проследить за значением перемен ной? •Л .«......
В л. *» Efrors «аггйпв» ws*“9«‘
£№»віічо«*(ІПа**япм«і«яп«і
Консоль ошибок не позволяет следить за переменными. К со ж ал ен и ю , п р и всех сво и х достоинстваих эту задачу ко н с о л ь о ш и б о к р е ш и т ь н е п о м о ж ет. Н о вам н и к т о н е м еш ает со зд ать свою собственн ую ко л со л ь, п р ед н азн ач ен н у ю и м е н н о для о тсл е ж и в а н и я зн а ч е н и й п ер ем ен н ы х .
530
глава 11
E r ro r C e n s o te
» Oear
,
охота на ошибки
Пользовательская консоль Т акая задача, как со зд ан и е со б с т в е н н о й к о н со л и , м о ж ет сн ач ал а п о к азаться с л о ж н о й , но ведь нам всего л и ш ь нуж но п о зап р о су о т о б р аж а ть о п р е д е л е н н ы й текст. П р о с т о о тл а д о ч н ая п а н ел ь до л ж н а д ел ать эт о н е в о тд ел ьн о м о к н е, а н е п о с р е д с тв е н н о н а ст р ан и ц е . В сплы ваю щ ее о к н о неудобн о потом у, ч т о п о л ьзо вател ю п о с т о я н н о п р и х о д и тс я щ ел к ать н а к н о п к е О К , ч то б ы его зак р ы ть. В51 Са$е 2: Winп'шg СаНе^
00в
О
Сообщения от ла д чи ка от ображ аю т ся в с м ц и а л ш о й об ла ст и в нижней ч а ст и ст раницы .
оаИНшл! 1 В каждой ст р о ч ке о т д ельн о е сообщ ение о т лад чика.
►с а И Н о т г оаХ Ш чв! саИ Н аи! оаИ Н чт:
2 3 4 5
Возьми в руку карандаш Представьте конструкцию консоли, позволяющей отображать список сообщений отладчика в динамически создаваемой области страни цы. Нарисуйте, из каких компонентов она должна состоять и как они соединяются друг с другом и со специальным объектом JavaScгipt, который и представляет собой консоль.
далее *
531
реш ение упражнения
Возьми В руку карондаш, Решение О т ла д о чн а я консоль п р е д с т а в л я е т содой о б ъ ект D e b u g C o m o k, обладаю щ ий одним сво й ст во м и одним м ет о д о м .
Вот из каких компонентов должна состоять консоль, позволяющая отображать список сообщений отладчика в динамически создавае мой области страницы.
DebugConsote
. Каждый вызов мет ода сИ5р1ауМ5д() приводит к появлению новой ст р о ч ки на консоли.
Сама консоль на ст р а н и ц е с о з д ает ся п р и п о м о щ и т е га div.
Л огическое свойст во sh a d e d м е н я е т свое значение с tr u e на raise и обрат но для каждого следую щ его сообщ ения, м ен я я ■ пр и э т о м ф оновы й цвет .
В нут ри т ега div, определяющ его вид ИТМ и -э л е м е н т ы для от ладочной област и динам ически с о з д а ю т ся ко нсо лью , т о е с т ь п о л ь зо в а т е л ю не нужно п и с а т ь никакого с п е ц и ального Н Т М и-кода для поддерж ки консоли.
консоли, располож ены дочерние т е ги d iv для от ладчика.
"callNum:
532
глава 11
от дельны х сообщений
div
2'
охота на ошибки
Магниты JavaScript в коде отладочной консоли отсутствуют несколько фрагментов. Заполните пробелы магнитами таким образом, чтобы получить объект В еЬ и дС оп зоХ е.
function DebugConsoleO //
Создание
области
{
отладки
); var
consoleElem
consoleElem.id
=
=
document.
"debug";
c o n s o le E le m . style. f o n t F a m . l y = m o n o s p a c consoleElem.style.color -
•
,
#333333 , (consoleElem);
document.body.
//
создан и е
( " h r " ) );
(document.
consoleElem.
с .о й с - .а ,
this.
у п р а .л я т е г о
и з м е н е н и е м ф о н о .о г о
цвета
= false;
} DebugConsole.prototype.displayMsg // С о з д а н и е с о о б щ е н и я var msgElement = d o c u
m e n t
=
function(msg)
.c r e a t e E l e m e n t ( d i v
{
),
msgElement. a p p e n d C h i l d (d o c u m e n t............................................) "#FFFFFF” n ^ s g E l e m e n t . s t y l e . backgroundColor
var
consoleElem
=
d o c u m e n t
изменение
this.shaded
значения
=
this.shaded
7
"#EEEEEE"
:
.g e t E l e m e n t B y l d (...............)''
consoleElem. a p p e n d C h i l d ( //
=
............
свойства,
лтпявпяюшего управляющего
изменением из
фонового
цвета
this.shaded;
msgElement
appendChild
"debug'' createElement
createTextNode
далее ►
533
решение задачи с магнитами
Решение задачи с магнитами Вот каким образом нужно было расположить магниты, чтобы по лучить код объекта О еЬ и д С о п зо 1 е.
function //
DebugConsoleO
Создание
var
области
consoleElem
consoleElem.id
=
=
{
отладки
createElement
document.
"debug"
c o n s o l e E l e m . s t y l e .c o l o r
appendChild
consoleElem.
11
Создание
this.
=
свойства,
shaded
к
=
"monospace
»consoleElem);
document
управляющего
т false;
,
"# 3 3 3 3 3 3 ";
appendChild
d o c u m e n t .b o d y .
div консоли добавляется т ело докум ент а, поэт ам и Консоль появляет п о я вля ет ся с я в нижней части ст раницы Гег
c o n s o leElem. style. f o n t F a m i l y
ichr"));
createElement
I
изменением
фонового
цвета
^ ^ ницы.
DebugConsole. p r o t o t y p e . d i s p l a y M s g = f u n c t i o n ( m s g )
{
// С о з д а н и е с о о б щ е н и я v a r m s g E l e m e n t = document .c r e a t e E l e m e n t (" d i v " );
m s g E l e m e n t .a p p e n d C h i l d ( d o c u m e n t . msgElement.style.backgroundColor
var
consoleElem
=
createTextNode =
this.shaded
document.getElementByld
.
Иербыи дочерний э л е м е н т — го р изон т аль-
Н ачальное значение false с о о т в е т с т в и е т
(msg) ) ;
белому ц ве т и ф она ее от ост альной с т р а Сообщения добавляются на консоль в дочерних т егах div.
; "#EEEEEE"
; "#FFFFFF";
"debug
c o n s o l e E l e m .a p p e n d C h i l d ( ~ m s ^ ^ ^ n t j | ) ;
/ , изм енение 3 » a . e „ , с . о й с т . а , у о р . . . я „ е г о „ з м е н ,» д е „ ф он»„го^ц^^^ th is .s h a d e d -
' | ; h i s .s h a d e d ;
/
чередуются. }
534
глава 11
черт
охота на ошибки
Отладка отладчика О уэн н е м о ж ет д о ж д аться м о м ен та, когд а н о в ая о т л ад о ч н а я ко н со л ь п о зв о л и т ему п о н я т ь , ч то ж е н е так со с ц е н а р и ем о б р а б о т к и зв о н к о в н а рад и о . О н и м п о р ти р у ет в стр ан и ц у ф а й л d e b u g . j s и со зд ает о б ъ ек т DebugConsole в заго л о вке. <script //
t y p e = " t e x t / j a v a s c r i p t ">
Глобальная
var
console
=
переменная new
отладочной
консоли
Э т о т код создает в заголовке ст раницы о б ъ ек т DebugConsole как глобалш ун? п е р ем ен н ую .
DebugConsoleO;
r ^ ~ ~ - _________ К со ж ал ен и ю , п л ан ам н е суж дено сбы ться. П е р в а я п о п ы тк а и с п о л ь зо в ан и я к о н с о л и п о к а зы в а ет, ч т о О уэн т о л ь к о увел и ч и л ч и сл о п р о б л ем , д о б ав и в с о в е р ш е н н о н о в ы е ош иб ки. ■Д
_____ _ ____
S i Alt ? Errors
ch
Error Con ole
ÿ
Messages
CD
J Clear Evaluate
Q ïwoKdocumenbboiJy has по properties.
Куда же пропали свойства тела документа? Ведь имен но в них хранится содержи мое веб-страницы.
■■
К аж ет ся, в сценарии появилась совсем н о вая о ш и б ка...
б р а у з е р сообщ ает , ^ т о в т е л е до к у м е н т а о т с у т с т в у ю т свойст ва.
С тавш ая п р и ч и н о й о ш и б к и с т р о ч к а код а д о б а в л я е т к телу до кум ен та д о ч е р н и й узел ( d i v ) , ч то п о и д ее н е д о л ж н о созд авать н и к а к и х п р о б л ем . document.body.appendChild(console);
П о л у чается, ч т о чего-то н е х в а т а е т и эт о ч то-то св я за н о с н о вы м о б ъ е к то м DebugConsole.
Ш ТУРМ Что могло стать причиной отсутствия свойств в теле документа?
далее >
535
как ут екает время...
За го ло во к ст раницы загруж ает ся перед ее т е л о м , п о э т о м у содерж имое п о с л е д него в э т о т м о м е н т недост упно.
0)кидание загрузки П р о б л е м а с о т л а д о ч н о й ко н со ль ю с в я за н а с в р е м е н е м загрузки с т р а н и ц ы и м о м ен то м , когд а код с ц е н а р и я п ол уч ает доступ к ее содерж им ом у.
Н Т М и -злем ен т ы ст ра н и ц ы загруж аю т ся т о ль к о п р и з а г р у з к е , т е л а , по сле з а г р у з к и з а головка.
<tltle>BSI Case 2- WH
■
• " “ "i n g C a U e r < / t i t l e > <3cript t y p e - t e x t / j a v a s c r i p t " s r c - ’d.h
•
avascript "> обальная переменндо
function checkwlnnpr<f // У величение
,
var callNum;
звонка на единицу
++callNum; // П роверка п обедителя
form.submitO;
'
"“"Ьег
callNum today\’s winner!");
else
{
» f —
s : : ~ г г
~ » .
c a l lerField.select o';
<body>
___
<form name="callform” a
c
t
,
.
'
'
--- --------
-tbod...posT..> "'oncLc\"-":?“r ° " ’' </html>
------- —
type...te«.. />
____ _____
Т®^а8сг1р1 в заголовке не имеет доступа к содержимому страницы. Т ак как сн ач ал а загруж ается заго л о в о к и т о л ь к о п о то м все о стал ьн о е, коду с ц е н а р и я н е д о л ж ен т р е б о в а т ь с я доступ к Н Т М Ь -элем ен там в т е л е с т р ан и ц ы . Э то о г р а н и ч е н и е м о ж ет п о к а заться ст р ан н ы м , н о о н о и м е е т см ы сл, есл и в с п о м н и ть, ч то п р а к т и ч е с к и весь код запускается и м е н н о в заголовке.
536
глава 11
охота на ошибки
А что по поводу функ ций в заголовке? Они тоже не работают?
Н е весь содержащийся в заголовке страницы код выполняется там же. П о м е с т и т ь ко д ф у н кц и и в за го л о в о к с т р а н и ц ы вовсе н е о зн ач а е т зап у сти ть ее там —ф у н кц и я запускается т о л ь к о п о сл е ее вы зова. А во т код, п о м е щ е н н ы й в за го л о в о к вн е ф у н кц и и , запуска е т ся сразу ж е п о сл е загрузки заголовка. И м е н н о эт о с т ан о в и т с я п р и ч и н о й пр о б л ем . О б ъ е к т DebugConsole н е л ьзя бы ло со зд авать в заго л о вке, т а к как его ко н стр у к то р за в и с и т о т со д е р ж и м о го в т е л е с тр ан и ц ы .
реш ение упражнения
Возьми в руку карандаш Решение
Вот когда следует создать объект DebugConsole, чтобы гарантировать его доступ к элементам страницы.
.БМУШ .ИШ Зывает нй .окончание И ? . . § . .Ü
?
.
оЫРЛ4.-. .Имен .?.-^?.' Сл создават ь о б ъ ект
console САедуеп% о с т а в и т ь в за го ло вке ст р а н и ц ы , ведь о б ъ е к т я вля е т ся глобальны м — к о н с т р у к т о р о б ъ е к т а б уд ет вы зван т о ль к о после собы т ия onload'......
^ МениВ
со^данигг
<body onload="console = new DebugConsole (); ">
ош и б ку, с Б я ЗанЕ^іо с KoHcojTbjo
__ __________ Т е п е р ь п о являет ся ß о т в е т на собы т ие onload.
Самая проти8ная ошибка
Ошибки при выполнении возникают при определенных условиях во время работы сценария.
П р о б л е м а с н езагруж аю щ и м ся тел о м д окум ен та о т н о с и т с я к о ш и б к а м п р и в ы п о л н е н и и —т а к и е о ш и б ки п о я в л я ю тся то л ь к о п р и о п р е д е л ен н ы х услови ях во в р е м я р а б о т ы с ц ен ар и я . П о д услови ям и м о ж ет п о д р азу м еваться и ввод п о л ьзо в ател ем о п р е д е л ен н ы х д ан н ы х и л и о п р е д е л е н н о е ч и сл о п о в т о р е н и й ци кла. О ш и б к и п р и в ы п о л н е н и и с л о ж н о об н аруж и м ы , потом у ч т о и х н е в о зм о ж н о п р ед сказать. И н о гд а п р о б л ем о й я в л я е т с я д аж е в о с п р о и зв е д е н и е о ш и б ки , н а ко то р у ю ж алуется п о л ьзо вател ь. Error Console
вв© Hj
в
‘ All ■ Errors
їй
!, warninas
Mtss«e«s
Oear [ Evaluate
„
f r r o c diicumentiKHiy
^ sour»file,
538
глава 11
no proiaertits
^
tins:
t
П роблем а с консолью о т лад ки от н о си ла сь к ош ибкам п р и в ы п о л нении и была вызвана п о п ы т к а м и до ст уп а к ещ е незагруж ен ны м данны м. Подобные п ро б лем ы во зн и к а ю т т о ль к о в процессе р а бот ы сценария.
охота на ошибки
Три самых популярных типа ошибок В м есте с о ш и б кам и п р и в ы п о л н е н и и л и д и р у ю т в Jav aS crip t еш;е два т и п а уже и зу ч ен н ы х нам и ош ибок: с и н т а к си ч е ск и е и л о ги ч еск и е. О н и могут п о я в л я ть с я в с ц е н а р и я х как вм есте, т а к и по отд ел ьн ости ! Д ля их усп еш н о го р а с п о зн ав а н и я и у с т р ан е н и я нуж но п о н и м ать разн и ц у между ним и.
Синтаксические
В о зн и каю т п р и н ару ш ен и и п р ав и л я зы к a Jav aS c rip и дел аю т код н е п о н я т н ы м д ля и н т е р п р ет а т о р а .
При Выполнении В о зн и каю т в п р о ц е сс е р а б о ты сц е н а р и я , н а п р и м е р , п р и вводе п о л ьзо в ател ем д ан н ы х , к о т о р ы е н ев о зм о ж н о о б р аб о т а ть , и л и п р и п о п ы тк е д оступа к ещ е н е со зд ан ном у объекту.
<html> <head> 2; Winning Caller</title> <title>BSI case "debug. js"X/script> ript type="text/Javascript" :="text/javascript" <script type^ ;~nehua conaole global ----console * new D e b u g C o n s ^ О ;
7
// Total number of calls var callNum = 0;
Логические В ы зван ы н е в е р н о й л о ги к о й и в о сн о в н о м св я за н ы с кодом , к о т о р ы й д о л ж ен в ы п о л н я т ь одну о п е р ац и ю , н о д ел а е т что-то дру гое. И н о гд а м огут б ы ть обусловле ны тем , ч то п р о гр а м м и с т с сам ого н а ч ал а н е в е р н о п о н я л задачу.
нение
function checkwinner(form caller; // Increment the call number
winningNum)
var callNum; ++callNum; con s o l e . displayMsg C'callNum;
allNum ) ;
a...dinner ^ I N u n . . "... t o d a y s wlnne.l"); a l e r t (caller form, submit 0 ;
I
Какому типу ошибки соответствует каждое из описаний.
О тсу тстви е ско б о к вокруг усл ови я в о п е р а т о р е i f . П е р е м е н н о й c o u n t e r н е п р и с в о е н о н а ч ал ь н о е зн а ч е н и е 0. . Ц икл, повторяю щ ий ся после последнего элем ента массива. О тсу тстви е закр ы в а ю щ е й ф и гу р н о й скоб ки у ф ункц ии.
далее *
539
реш ение упражнения
ПраЖ НгН Иб
типам ош ибок соответствуют данны е описания:
решение Синтаксическая
О тсу тстви е ско б о к вокруг усл ови я в о п е р а т о р е i f . П е р е м е н н о й c o u n t e r н е п р и с в о е н о н а ч а л ь н о е зн а ч е н и е 0.
Логическая
Ц и кл , п о в т о р я ю щ и й ся п о с л е п о сл ед н его эл е м е н т а м ассива.
.
О тсу тстви е закр ы в а ю щ е й ф и гу р н о й ско б ки у ф ункц ии.
Почему номер звонка отображается как «не-число»...
Э то не-чисАо Т е п е р ь , когд а к о н со л ь отл ад к и г о то в а и к о р р е к т н о р аб о т а ет , п р и ш л о в р ем я в ы я сн и т ь , ч то ж е н е т а к с н аш ей п е р е м е н н о й c a llN u m . Эту проб л ем у Оуэну д авн о уже сл едовал о р еш и ть. П е р е м ен н а я c a l l N u m о т о б р а ж ае т с я как NaN, т о е с ть и м еет н еч и сл о в о е зн а ч е н и е. В от т о л ь к о почему?
console.displayMsg("callNum:
Эта ст рочка задает слежение за переменной
" +
callNum)
CD
BSI Case 2; Winning Cailer
^ М З ..о
callNum.
По крайней м ере, консоль отладки работ ает !
540
глава 11
Caller палю; |Next caller callMums caiiNums callNums callNumt саІІЯиш:
KaK HaH HaN NaN NaS
Call
охота на ошибки
Когда сАе)кения недостаточно И н о гд а о т с л е ж и в а н и е з н а ч е н и й п е р е м е н н о й п р и н о с и т б ольш е в о п р о с о в , ч ем о т в е то в . Н у почем у п е р е м е н н ая c a l l N u m н е я в л я е т с я числом ? П о ч ем у ее зн а ч е н и е н е у вел и ч и в ается н а еди н и ц у п р и каж дом следую щ ем зв о н ке? З а ч е м нуж на к о н со л ь отлад ки , есл и о н а всего л и ш ь п о д тв ер ж д а е т т о , ч т о м ы и т а к зн аем , т о е с ть т о т ф акт, ч то у н ас п р о б л ем а. И как нам н а й ти п р и ч и н у т ак о го п о веден ия?
А теперь что?
А может быть, начать удалять код, пока номер звонка не начнет менять свое значение.
Удаление кода позволяет упростить сценарий.
П р и о тлад ке с ц ен ар и е в Jav aS crip t б ы в ае т и так, ч то д ей ству ет п р ав и л о «чем м ен ьш е, тем лучш е». В от и в д ан н о м случае и м е ет см ы сл удалять ф р а г м ен ты ко д а и с м о тр е т ь, ч т о п олучается. Х отя н а сам ом д ел е н ам нуж ен всего л и ш ь сп особ н а в р ем я д еа к ти в и р о в а т ь код, а н е удалять его. Ведь п осл е за в е р ш е н и я о тлад ки с ц е н а р и й ж ел ател ьн о в о сс та н о в и т ь в п е р в о н ач ал ь н о м виде.
далее *
541
испорченный комментариями
Комментарии Д е а к т и в и р о в а т ь код в п р о ц е сс е о тлад ки л е гч е всего, п р е в р а т и в его в к о м м е н т а р и и . И м е н н о э т о т сп особ д ает во зм о ж н о сть и зо л и р о в а т ь ош ибку.
function checkwinner(form, caller, winningNum) console.displayMsgC'callNum; " + callNum);
Комментарии позволяют на время деактивировать фрагменты кода.
{
/*<=-------
// Increment the call number var callNum; ++callNum;
// Check for a wil iner if (callNum == wil' ningNum) { caller number alert(caller + winner!"); form.submit();
callNum
today\'S
} else { // Reset the caller field for the next caller var callerFieLfi = document.getElementByld('caller ); callerField.^lue = "Next caller"; callerFielcVfocus 0 ; callerField.select 0;
) */ « )
Э т о т м но го ст р о чны й ком м ент арий о т к л ю ч а е т весь код ф ункц и и за и с клю ч ен и ем ст р о чки от ображ аю щ ей сообщ ение от лад чика. П ерем енная саНЫит т еперь им еет значение О, зн а ч и т , пр и ч и на п р о б лем ы в о т к л ю ч е н н о м коде.
Ш Т У РМ Что произойдет, если вернуть только строчку, увели чивающую значение переменной на единицу?
542
глава 11
Теперь номер звонка показан как 0. Значит, именно фрагмент изолиро ванного кода становится причиной появления значения NaN.
охота на ошибки
Проблема ка)кется решена П е р е й д я о т м н о го с т р о ч н ы х к о м м е н т а р и е в к о д н о с тр о ч н ы м , м ож н о в ы б о р о ч н о п о д о й т и к о тк л ю ч ен и ю кода. П о сл е д обавл е н и я с т р о ч к и , у вел и ч и ваю щ ей зн а ч е н и е п е р е м е н н о й c a llN u m н а еди ниц у, все н а ч и н а е т р а б о т а т ь как нуж но. З н ач и т , п р о б л е м а с о д е р ж и т с я где-то в о тк л ю ч е н н ы х с т р о ч к ах кода. function checkwinner(form, caller, winningNum) console.displayMsg("callNum: " + callNum);
О дност рочны е к о м м е н т а рии п о зв о л я ю т о т к л ю ч а т ь и в к л ю ч а т ь обрат но о т - " дельны е ст р о ч ки кода.
// Increment the call number // var callNum; ++callNum; -----------— ■"
e© 0
С нят ие значка к о м м е н т а р и я с эт о й ст р о ч ки наконец ----- т о за с т а в л я е т п е р е м е н н у ю ^ ca llN um ко р р ект н о ф ункцио пироват ь.
Check for winner if (callNum == winningNum) { // alert(caller + ", caller number winner!"); 11
p
{
//
+
callNum
today\'s
m Case 2: Wmning Caller
Id for the next caller iment.getElementByld('caller'); iext caller";
Т еперь значение п е р ем ен н о й callN um увели ч и ва ет ся на единицу при каж дом звонке, как и п р ед п о ла га ло сь с с а м о го начала.
далее ►
543
реш ение упражнения
Возьми В руку карандаш, Решение
Вот что было не так с переменной callNum.
6 .с л у н а й т . ш М н л .ф;ш . о.днл,. локялшйя ш р.е. .М^ат^.Она<<перекр_ы6ае^ м ^_ еш н н ую _ callN um . Ч . 9 . > . и н и ц и а л и з и р о в а н а ,
увеличе-
^ >^олАе^ом-победит елем д ает в р е з у л ь т а т е значение « n o t а n u m b e r» . Д л я исп р а влен и я ош ибки дост ат очно у д а л и т ь с т р о ч к у , в ко т о р о й создает ся э т а перем енная.
//
У д ал ен и е c3nj>o4Ku, со зд аю щ ей Л о к з д ь ^ ю
Увеличение
++callNum;
^ ^ е м е н і^ ю , у о п Р а н я е ш ош ибку # 4 .
номера
\
звонка
на
единицу
Убрав э т у с т р о ч к у , в кот орой случайно создает ся ло к а льн а я п е р е м енная ca llN u m , м ы за с т а в л я е м ф ун к ц и ю и сп о льзо ва т ь гло б а льн ую перем енную callN um , ко т о р а я п р е д по ла га ла сь с сам ого начала.
Два}кды объявленные переменные П р и ч и н о й о ш и б ки в с ц е н а р и и о б р а б о т к и зв о н к о в стал а д в а ж д ы о б ъ я в л е н н а я п е р е м е н н ая c a llN u m . Т а к а я п р о б л ем а в о зн и к ает, когд а и м я л о к а л ь н о й п е р е м е н н о й дублирует и м я гл обал ьн ой . П р и это м все и зм е н е н и я л о к а л ь н о й п е р е м е н н о й н и к ак н е о тр аж аю тся н а с о с т о я н и и гл о б ал ь н о й — о н а как бы н а в р е м я с к р ы в а ет с я о т сц е н а р и я.
Двойное объявление возникает, когда локальная и глобальная неременные создаются нод одним именем.
Глобальная
переменная.
Глобальный код tcallNum;
Локальны й код Локальная
++callNum;
перем енная.
Одно и т о ' же им я!
544
глава 11
Э т о т код на единицу — ув е л и ч и в а е т гло бальную перем енную , давая в р е з у л ь т а т е 6. Э т о т код у в е л и ч и в а е т на ед и н и т ло к а л ь н у ю п е р е м е н н у ю , давая о р е з у л ь т а т е 1 — глобальная п ер ем ен н а я п р и э т о м своего з н а чения не м ен я е т .
охота на ошибки Часзп' '^ а Д а Б а е М ы е БоЛ роС ь!
Б
А как понять, какие строчки кода следует превратить
в комментарии?
0 ; Вы научитесь отвечать на этот вопрос по мере роста вашего опыта в отладке сценариев изуаЗспр!. Впрочем, обычно имеет смысл изолировать большую часть или весь код вокруг проблемной области. В случае больших проблем можно начать с превращения в комментарии всего кода. Не забудьте также удалить теги, импортирующие внешний код. Если вы уже нашли содержащий ошибку фрагмент, используйте другой подход. По очереди превращайте в комментарии строчки, пока ошибка не исчезнет. То есть вместо отключения всего кода и постепенного его включения до появления ошибки вы по одной выключаете строчки, пока ошибка не исчезнет.
Первый подход применяют в случаях, когда непонятно, где именно локализована ошибка, в то время как второй используется после обнаружения дефектного фрагмента.
Б: Можно ли намеренно дважды объявить переменную?
О
! Это все равно что спросить, можно ли намеренно сломать себе ногу? И ответ на это — нет. То, что вы самостоятельно причиняете себе боль и страдания, не делает их приемлемыми и допустимыми. Кроме того, код зачастую и так содержит достаточно ошибок, чтобы еще вносить их специально. Поэтому двойного объявления переменных следует избегать в любой ситуации.
Дело закры то!
Дело закрыто! ) о.
Б л аго д ар я своем у т е р п е н и ю и н аш ей п о м о щ и О уэн завер ш и л отладку п р о гр ам м ы и получил д о л ж н о сть те сти р о в щ и к а.
О уэн , о п ы т ш о т лад чик сце-нариео JavaScript■
с а И Н и т !
1
о а Н Я и т !
5
са1Мц»5 2 о л И М о я ! 3 оаИНиш! 4 саИНа»! с а 1 1 8 и т
А!ап. саИег пытЬег 7...1ойау*$ \«тпег1
К о р р е к т н о р а б о т а ю щ и й код щ е н а р и я р адиоигры оснащ ен ко нсо лью от ладки. далее >
545
конт рольная проверка
•
Хрнтролъная таблица Оуэна (убедись, что все скобки имеют пару. ^
‘П едись,чт о
заключены в ско^т ,— аккуратные
отступы помогают определить границы блощ.
Кзеегай опештвке иштх.ги:решиныхи функций — »^ случ1Ш_итошдоштем.тстъ е иж на^аш т виш я причтои проблем. (Будь последователен в жполъэовании павычекм фов и при необходимости ак^ратно смешиваи ю с в Я Ш Ь -
атрибутаХ; Символы со спеицалъным значением не забывай заменять escев символами, например (\")для павычеки ( \ ) д л я апострофов.
уГикргда не используй оператор = ш ^Г' ЗаУоЗспрг и не считает это ошибкри, но код будет раЬо-
Х от я
тать вовсе не так, как,^^^ нужно. это ОГеред ссылкой на объект убедись что он уже создан, особенно касается элементов веб-страницы, которые создаются только после появления события onload.
Ш когда не присваивай мжальным и глобальным переменным о д ^ к о в ы е имена, ведь в этом случае м>кальтя переменная начинает использоваться вместо глобальной, и поведение сценария становится непредсказуемым.
546
глава 11
охота на ошибки
Вкладка Согните страницу по вертикали, ч т о б ы совместить два мозга и р е ш и т ь задачу.
Чего заслуживают дефекты кода? --------------- - Ум' хо|^оШо, а два лучте!
---- -------
Подставлять дру1ую щеку — неправильный подход, который может истощить ваше терпение. Отвращение к борьбе с дефектами ослабит ваш код а это уже проблема.
Ih
и н а М и Ч е с К и е
Д а н н ь хе
%
Удобные веб-приложения ,
Современный Интернет очень ОТЗЫ ВЧИВ, страницы умеют реагировать на каждый каприз пользователя. И м енно об этом мечтаю т многие разработчики. JavaS cript играет важную роль в о сущ ест влении этой мечты при помощ и технологии Ajax, позволяю щ ей эф ф ектив но менять «чувствительность» страниц. Благодаря A jax страницы научились
быстро загружаться и динамически сохранять данные, отвечая на дей ствия пользователя в реальном времени без необходимости перезагрузки б раузера.
.
хочу больш е динамических данны х
Жа)кда динамических данных
Добавление в блог YouCube новых записей не должно требовать редактирования кода страницы.
Помните Руби, фанатку головоломок и автора блога? Руби обо жает свой блог YouCube, написанный с применением JavaScript, но она устала редактировать H T M L -файл при добавлении каждой новой записи. Поэтому она хотела бы отделить записи в блог от H T M L -кода, описывающего страницу, чтобы сосредо точиться только на создании новых постов. в Ов YouCube - The Blog for Cube Puulers
Мне хотелось бы
о ~
-
SearehttmWogJ
новые записи в блог без редактирования НТМи-кода.
Ш night а Siuge о й » was chasing як, and St !rept уеШщ шу i
ЄbackwMds...Ybur!
-ЯиЬ>’ W o w
%it took me a month but Ehc new cube is fmiOiy solved?
/ / Returr a for»atte BEog .prototype.toHTHI / / Use a gray back( I var blogHTML »
rate tlie for
7*7*7 cube. CoaB be my last blog post for a whUe...
^ T M L += “<stn
9^/2008
Attended a tally ouBide of a local азу store
that ssjpped carrying cube puzzles. Powei’to й!е puzzlers
if a 7x7x7 cube. Mixed feelings.
Random Snsfotiy i
.І'ьі^гГГ“
w Date(“08/19/2008")),
ordered the scory 7x7x7 cube. Stortina n m^t-rn feelings.", new Date('"88/29/2008''^^ oily outside of 0 local toy stor» thot stopped corrylm^r!^ reginen to p r e p a r e . n e u ' ----------к-*-*-!®*, r uPwo e^rr t oto t the ou^,l.„i7x7x7 cube. Could be .y lost blog ‘= * " Date("09/03/2008")), о wh le... , new Date(“09/05/2008")), me a couple of weeks but the f.nolly S O I « , - , ne„ -cube777.p„,.)
0ateCm/ei/2m-))
Уставший владелец Ьлога Руби...
550
глава 12
Ч т о б ы до бавит ь н о вцю за п и с ь , Руби до л ж н а р е д а к т и р о в а т ь H T M L -ф а й / с т р а н и ц ы YouCube.
динамические данны е ф айлы с новой версией блога Руби м о ж н о с к а ч а т ь т у т к!:Ь р'.//\м \ы ^.
Блог, управляемый данными Руби на пороге новых открытий. Версия блога, разделяющая содержимое и структуру страницы, связана с динамическими данными, которые в реальном времени вставляются в страницу, в то время как сама страница обрабатывается браузером. Соот ветственно, нам нужен блог, управляемый данными. Его веб страница будет всего лищь определять структуру, в то время как содержимое будет меняться при помощи данных.
д а н н ы е блога х р а н я т с я б о т ^ _ К е л ьн о м ф ай ле , ко т о р ы й м о ж но р е д а к т и р о в а т ь н езависим о
от
в е б
-страницы.
Д а н н ы е б л о га
Веб-страница Г.,«,...
В е б -с т р а н и ц а с о д е р ж и т Н Т М и -к о д , опре д е л яю щ и й ее с т р у к т у р у , а т а к ж е ко д J a v a S c rip t для вст а вки в с т р а н и ц у д и н а м и ч е с ки х данны х блога.
З а п и си блога в с т а в л я ю т с я в с т р а н и ц у из от дельного ф айла.
JavaScript о т в е ч а е т за о б р а б о т ку данны х блога и в с т а в к у их в в е б -с т р а н и ц у .
С помощью JavaScript строчки данных блога динамически вставляются в H T M L -код и генерируют окончательный вариант страницы блога YouCube, выглядящий точно так же, как и рань ше. Н о управляемая данными страница состоит из двух частей: структура страницы и данные блога. Благодаря тому, что запи си содержатся в отдельном файле, Руби больше не понадобится вмешиваться в код HTML, CSS и JavaScript.
y<wCube ■The Blog for Cube P om U*»
Руби н у ж н о редакт ироват ь Т о л ь к о ф айл с д а н н ы м и блога.
m bfPtakrЫ >у
youcube.html
blog.xml
далее >
551
дорога ложка к обеду
Кажется, работа с динамиче скими данными очень сложна и требует большого количества кода JavaScгipt.
Н ебольш ие дополнительны е усилия по написанию кода вознаграж даю тся в конце. Разумеется, написание страниц, управляемых данными, требует дополнительного программирования, но в ре зультате вы получите возможность быстро и легко обнов лять их содержимое. Кроме того, вJavaScript существует встроенная поддержка динамических данных благодаря современной технике программирования, называемой Ajax.
552
глава 12
динамические данные
Ajax как возмо)кность для общения Ajax дает возможность работать с динамическими данными благо даря постоянному обмену небольшими сообщениями между браузе ром клиента и сервером. Сценарий может запросить данные с сер вера, например набор записей блога, а сервер доставляет их при помощи технологии Ajax. Сценарий же берет полученные данные и динамически вставляет их в страницу.
позволяет веб-страницам динамически получать данные с сервера.
К л и е н тска я ст р а н и ц а
запрам ибает с данные блога п р и т ехно л о ги и AjaKК л и е н т д е л а е т за п р о с A ja x и ж д е т от вет а.
Р
J a v a S c rip t с л у ж и т п о с р е д н и к о м , вы полняя з а п р о с , обрабат ы вая о т в е т и о ст авляя п о лученны е данные в в е б ст раницу.
</head> ■
Щ
</so<SS>
Щ
і ^
youcube.html
Б р а узе р .
^
С ервер п о л у ч а е т з а прос и от правляет о о т в е т за п и с и блога.
. Клиент С т б е р оо т т б^еч ча лі ^еГ т-
„
ьіод.хті
за п исе й олога.
П олучив о т в е т сервера, кл и е н т бе р е т за п и си блога и м гновенно о ст а в л яе т и к в веб с т р а н и ц у , не т р е б уя ее п е р езагр узки .
Ш Т У РМ Что о зн ач ает « X M L » в контексте записей блога? Каким образом он пом огает работать с динам ическим и данны м и?
далее >
553
htm l под другим именем
HTML для любых целей: XM L Буквы «ML» в аббревиатуре H T M L расшифровываются как «язык разметки» и указывают на то, что язык H T M L исполь
зует атрибуты и теги для создания гипертекста («НТ»), X M L это еще один язык разметки, используемый для создания всего, что вам будет угодно. Именно па это указывает буква «X»! Ведь существуют различные типы данных, которые имеет смысл сохранить при помощи тегов и атрибутов. Так почему бы не создать для них расширенный язык разметки?
IB 1 4 T M L
XML — язык разметки для форматирования данных любого типа.
Веб-ст раница.
badtwaf(l».-.Yl№!
З а п и с и блога.
Основным достоинством языка X M L является его гиб кость. В отличие от HTML, имеющего фиксированный набор тегов и атрибутов, X M L всего лишь задает правила их создания и использования. И каждое построенное на X M L приложение может по-своему воспользоваться ими для представления определенной информации.
554
глава 12
!.. Powa- №(he pusden’
динамические данные
форматирование с помои^ью XM L Прелесть языка X M L состоит в возможности самостоятельно соз давать теги и атрибуты, подгоняя язык под свои цели. Существу ют и предустановленные варианты XML, заточенные на решение определенных проблем, и ими вполне можно воспользоваться при необходимости. Н о сложно воспротивиться искушению соз дать свой собственный вариант языка.
Как и код HTML, код XML сост оит из и е р а р х и и эле м е нт о в.
<movie>
Каждый ф рагм ент и н ф о р м а ц и и о ф и л ьм е х р а н и т с я между своими со б ст в е н н ы м и т е га м и .
<title>Gleaming the Cube</title> <releaseDate>01/13/198 9</releaseDate> <director>Graeme Clifford</director>
<Summary>A skateboarder investigates the death of his adopted brother.</summary>
</movie>
Инф ормация
Несмотря на то что раньше вы никогда не видели такого языка разметки, ведь он полностью со,здан пользователем, названия тегов дают возможность понять назначение данных. Более того, теги связаны с заключенной внутри них информацией — вполне логично использовать тег <director> для хранения сведений о режиссере фильма!
■о ф ильм е з а ключена в т ег <m ovie>.
Соедините показанные ниже теги с соответствующим описанием и укажите, к какому язы :н 2 н и е
ку — HTML или XML — принадлежит каждый тег.
<itunes:author>
Выделение жирным текста на странице.
<span>
Заголовок новостей.
<title>
Элемент управления вводом данных.
<strong>
Преобразованный в речь текст для звонящих по телефону.
<input>
Автор цифровой записи 1Типе5.
<prompt>
Выравнивание содержимого веб-страницы.
далее >
555
реш ение упражнения
Вот какое описание соответствует каждому из тегов. ^ п р а ж н ш е
решение ....
.. <зрап> — ... _НТМи
Выделение жирным текста на странице.
<ltunes :аиЪЬог>
<11Ъ1е>
---- Заголовок новостей. ”’”^ 4
Элемент управления вводом данных.
<зЪгопд>-- -- Преобразованный в речь текст для звонящих \ телефону. .. <1приЪ> -------Автор цифровой записи [Типез. ...
Выравнивание содержимого веб-страницы.
<prompt>
X M L — это Всего лишь те к ст Как и HTML, X M L -данные — это всего лишь текст, соответствен но, хранятся они в текстовых файлах. Н о файлы X M L имеют расширение .xml, в то время как для H T M L -файлов используется расширение .html или .htm.
Х М L -д а н н ы е хранят ся в ф а й л а х с расш ирением .x m l.
С?
blog.xml
556
глава 12
динамические данные
XHTML — это версия HTML, придерживающаяся более строгих синтаксических правил XML.
X M L + HTML = XHTML Несмотря на различные расширения файлов, X M L и H T M L связаны друг с другом, и эта связь называется X H T M L . Это со временная версия HTML, следующая более строгим правилам языка XML. Например, каждому открывающему тегу должен соответствовать закрывающий. В H T M L это правило для таких тегов, как, например, <р>, соблюдать не обязательно.
HTM L
XHTM L
This is а paragraph of text in HTML.<p>
<p>This is а paragraph of text in XHTML.</p>
8 HTML т ег <p> часто использует ся сам no ce5e~ указывая на начало или конец параграфа.
8 XHTML каж дом у о т к р ы в а ю щ е м у т е гу должен соот вет ст воват ь за к р ы ва ю щ и й .
Другим важным отличием H T M L и X H T M L являются пустые теги, такие как <Ьг>, которые теперь комплектуются пробелом и косой чертой, указывающей на отсутствие закрывающего тега. XHTM L
HTM L This is just a sentence.<br>
This is just а sentence.<br />
Г B o m т а к в H T M L вы гл я д и т т ег переноса ст роки.
содерж ит
еще и пробел с косой черт ой Нй конце. ^
В отличие от H T M L в X H T M L в кавычки заключаются все значе ния атрибутов. HTM L
XHTM L
<а href=home.htnil>Go home</a>
<а href="home.html">Go home</a>
О т сут ст вие кавы чек в о кр у г значения ат рибут а наруш ает правила X H TM L.
Все значения а т р и б у т о в в X H T M L до л ж н ы бы т ь за кл ю ч е н ы в ка вы чки .
Хотя для нужд Руби X H T M L не требуется, он прекрасно иллюстрирует некоторые синтаксические правила языка XML, на пользовательской версии которого и будет написан новый вариант блога.
далее ►
557
XHTM L против XML
Беседа у камина HTML и XML конкурируют за данные.
^ T M L :
.-«чг-
Последняя версия HTML была переф орм улирована с п о м о щ ью XM L и п о л у ч и л а назва ние X H T M L .
------------XML:
Знаешь, ты для меня все запутал. Я был опо рой Интернета, а теперь из-за тебя люди стали путаться.
Н о вот со мной тебе не повезло, потому что браузеры до сих пор отображают только НТМЬ-код. А что делать с тобой, они не представляют.
О чем ты говоришь? Кого заботят данные, не имеюш,ие внешнего вида?
Не моя вина, что ты думаешь только о веб страницах. Я просто имею более широкие взгляды и потому представляю данные любого типа.
Вот такой я загадочный парень. Я — суш;ество без лица. Я не имею внешнего вида. И когда мне нужно показать себя, прибегаю к твоим услугам.
Вот только пе надо выходить из себя. Весь мир давно работает с данными, которые часто не видны. Банковские транзакции, политические опросы, погодные условия и многое другое. И все это можно увидеть только благодаря мне! Это так, но вот только каким образом это все хранится перед тем, как отобразится браузером? Совсем не в виде абзацев и та блиц. Они сохраняются с моей помощью, плюс я облегчаю обработку данных. Вот как... То есть ты утверждаешь, что м ы фактически работаем в паре? Именно так! Я не имею понятия о том, как выглядят данные, зато фокусируюсь на их значении. И пока люди пользуются браузера ми, для отображения данных мне нужен ты. Приятно было это узнать!
558
глава 12
динамические данные
XM L u данные блога YouCube X H T M L является замечательным приложением XML, быстро улучшающим структуру и надежность веб-страниц. Н о для блога YouCube Руби понадобится пользовательский вариант языка XML, моделирующий нужные ей данные. Давайте посмотрим, как представить записи блога при помощи тегов XML.
YouCube - The Blog, for Cube Puzzlers Blog.prototype.signature
<entries> <entry>
= "by Puzzler Ruby";
реш ение упражнения
Возьми В руку карандаш Вот вариант языка XML для хранения записей блога.
Решение
Блог н й ~ - '^ Ь 1 од> У одиился м еж д у h r Cube P u z z le rs < /title > 1^егам и <Ь!од>, < a u th o r> P u z z le r R u b y < /a u tk o r> V „_ _ _ T e z < title > с о д е р ж и т ...................................................................................................... заголовок- -оло-га............
.......................... Ш к р _ записеи хранит СЯ в т еге <en tries>.
..........................................
< d a te > ll/1 4 -/2 0 0 7 < /d a e e r .......cube I o rd e re d . I t ’s a re a l p e a r l. < / b o ^ >
..
< /e n tr u ^ i^
— ■ о т д е льн а я за п и с ь .....Зй^л.^ченй ,6 тег. .<£ntsry>.. т ело з а и дат а. п и си 'блогй' ■заключеныв свои собст венны е т еги.
................ </blog>
_
Часщо
^адаБ аеМ ы е B o iij> o c : b i _ >А почему не хранить записи блога в виде обычного, не форматированного текста?
О
^ ! Вы можете хранить их в таком виде, но потом будет неимо
верно сложно разбить информацию на набор записей, каждая из которых связана с отдельной датой. XML структурирует данные предсказуемым образом, позволяя легко выделять отдельные записи, не говоря уже о заголовке или имени автора блога.
5= Как XML связан с Ajax? С ! Название Ajax образовалось как сокращение от «Asynchronous JavaScript And XML» (асинхронный JavaScript и XML), так что XML непосредственно связан с Ajax. В настоящее время роль технологии Ajax расширена настолько, что для нее не всегда требуется XML. Но именно этот язык формирует осно ву большинства Ajax-приложений, предоставляя замечательный механизм моделирования данных.
Насколько для записи данных блога в формате XML нужен тег < e n t r i e s > ? Q : НЕ являясь обязательным , этот тег делает данные более структурированными и легкими для понимания. Например, в предыдущем примере без тега < e n t r i e s > оказалась бы невозможной поддержка множественных тегов < e n t r y > , остались бы только теги < t i t l e > и < a u t h o r > . Тег
< e n t r i e s > предполагает наличие набора записей и делает более очевидным способ использования данных.
560
глава 12
Как вы увидите в этой главе, связь между Ajax и XML обнару живается также в способе поддержки технологии Ajax языком JavaScript. В качестве формата данных для обработки запросов Ajax JavaScript не ограничен языком XML, но именно этот язык упрощает обработку этих запросов. Так что хотя некоторые пуристы и утверждают, что XML никак не связан с Ajax, на самом деле они идут рука об руку.
динамические данные
Я до сих пор не понимаю, почему, сохранив данные в опреде ленном формате, мы делам их дина мическими?
Сам по себ е форм ат XML не делает данны е динамическими, но он связан как с технологией Ajax, так и с DOM. Именно формат X M L чаще всего используется в Ajax, и, следовательно, именно в нем логично представлять данные, которые будут пересылаться на сервер и обратно в управляемой данными версии блога YouCube. Именно вы сокая структурированность языка X M L делает его идеаль ны м для пересылки данных. А сходство X M L с H T M L (XHTML) делает возможным применение D O M для доступа к X M L -данным, представ ленным в виде дерева узлов. То есть вы можете написать код JavaScript, проходящий по дереву X M L -узлов, аккурат но изолировать нужные вам данные и затем динамически встроить их в веб-страницу. Именно это делает X M L наи лучшим решением для построения динамических страниц, управляемых данными.
далее >
561
добавляем ajax
Добавим к блогу Ajax Имея на руках документ X M L с записями блога, Руби готова ди намически вставить их на странипу YouCube при помощи Ajax. Каким же образом A jax динамически вставляет XM Lданные в страницу?
©
I
Сервер получает запрос и начина ет ф орм ирование ответа.
Серве|» Х ш т йЯ
Запрос в основе работы Ajax концепция запро сов и ответов, означающая поддержку обмена данными между клиентом и сер вером.
Запрос п р е д с т а вл я е т содой и м я X M L -ф айла с з а п и с я м и блога.
О
Y c w C u b e -T h e B
т
Б р а у з е р о тп р а в л я ет серверу запрос
О
и ж д е т о тв е та .
До от правки
A j a x -за п р о са
ст раница не и м е е т данны х и п о т о м у не мож ет о т о сразит ь з а п и с и блога. youcu6e.html
562
глава 12
динамические данные
С е р в е р с о з д а е т о тв е т д л я б р а у з е р а ,у п а к о в а в д а н н ы е в ф а й л Ы од. В о т в е т во звр а щ а е т ся с о д е р ж и м о е X M L -ф а й л а с з а п и с я м и блога.
blog.xml
Ответ
Сервер
И ногда для обра б о т ки за п р о с о в A ja x и п о д г о т о в ки о т Ь е т н ы к д а н ны х т р е б у е т с я сцена р и й на ст о р о н е сервера.
о
..., ТвиСи&е~Пж»О ДfefСиЬеPut*»-*' Y o u C u b e - T h e В1<% Гог C u b e P u a d e rs
Браузер распако вы вает полученны е Х М Ь д ан н ы е и акку
„SMTChrteSoiif..........
'■-
9/24/2008 a b u ^ соЬс w » chastof me. snd it faq« yeHmg щ name
ратно вставляет и х 9/19/2009
в страницу.
Wow. Цюок me a niMth but me ПС» cube h Anally .-Mlved!
Ь Piaster/1ы1>у 9/SOM
9/3/2008
После вс 1т а 6к и Х М и -д а н н ы х о Н Т М 1 ~ к о д с т р а н и ц ы они ст ановят ся видим ы в б р а у зере.
tМ
аЮ с « 1 ^ppedcarrying„.ЬсpcvJ«.
«*
8Л »М ев
м
youcu5e.html •в ттштт т щ т щ г ^
Ш Т У РМ
На с т р а н и ц е р а б о т а е т код JavaScript, о т в е ч а ю щ ий за создание за п р о са Ajax и о б р а б о т ку о т в е т а .
Какой им енно код JavaS cript отвечает за обработку запросов A jax и ответов на них?
далее ►
563
что касает ся JavaScript
интерфейс XMLHttpRequest BJavaScript существует встроенный объект XMLHttpRequest, инициирующий запросы Ajax и обрабатывающий ответы. О н достаточно сложен и содержит набор методов и свойств, кото рые и осуществляют поддержку технологии Ajax.
readyState Текущее состояние объекта; О (неинициализирован), 1 (открыт), 2 (отправка данных), 3 (получение данных), 4 (данные загружены).
/
/
status
V
( \
О бъект X M LH ttpR equest и м е е т и другие свойства и м е тоды, но т у т перечислены самые важные из них.
abort() XMLHttpRequest
Отмена текущего запроса.
НТТР-код статуса запроса например 404 (не обнаружено) или 200 (ОК).
Э т от м ет од п р и м еняет ся, чтобы от м ен и т ь сделан ный запрос.
Эти свойства определяю т . 5ыл ли получен к о р рект ны й о т вет на запрос Ajax.
open О Подготовка запроса путем указания его типа, U R L и других параметров.
onreadys tatechange
send()
Ссылка на функцию, вызываемую при измене нии состояния запроса.
responseText
Отправка запроса на сервер для об работки.
S Эти два мет ода и с пользую т ся в паре ОЛЯ подготовки запросов A jax и их от правки на сервер.
Текст ответа на запрос.
t Это уникальное свойство содержит ссылку на специ альный обработчик собы т ия, кот орый вызывается при изменении состояния — именно он обрабатывает от вет ы .
564
глава 12
responseXML Текст ответа на за прос в виде дерева X M L -узлов.
J
Э т и два свойства хранят данные, п о лученные с сервера в о т в ет на запрос.
динамические данные
Применение XMLHttpRequest Объект X M L H t t p R e q u e s t — потрясающе мощный и удивительно гибкий. Н о мощность и гибкость сопровождаются сложностью, в результате даже базовые запросы Ajax требуют изрядного количества кода JavaScript. Частично за это в ответе несовместимость различных браузеров. Удруча ет также возможность легко запутаться в параметрах настройки объекта даже в случае, когда вам требуется только быстрое динамическое пере мещение данных. Рассмотрим в качестве примера код создания объекта X M L H t t p R e q u e s t , работающего с различными браузерами; var request = null; if (window.XMLHttpRequest) try {
Объект XMLHttpRequest является мощным, но сложным в ис пользовании инстру ментом.
Различны е подходы к со зд а н и ю о б ъ е кт а X M L H ttp R e c ^ u e s tj т а к к а к он п о -р а з н о м у п о д д е р ж и в а е т с я р а зн ы м и в е р с и я м и б раузера IE.
{
request = new XMLHttpRequest{); ■fer } catch (e) { request = null; }
// Пробуем версию ActiveX (IE) } else if {window.ActiveXObject) { try { request = new ActiveXObject{"Msxml2.XMLHTTP ) ; // Пробуем объект ActiveX более старой версии I E } c a t c h (е) { ttry request = new ActiveXObject("Microsoft.XMLHTTP"
о д ска зка Создание объекта X M L H ttp R e q u e st
. J
} catch(e)
{ request = null; O n e m m o p t r y - c a t c h являет ся усо в ер ш е н с т во в а н н ы м м е х а н и з м о м о бр а б о т ки о ш и б о к испо лне ни я о J a v a S c rip t.
затруднено тем, что для ка ж д о го браузера тр е буется своя реализация. К счастью, набор методов и свойств од и н аков для всех браузеров — учи ты вать ра зни цу в браузерах требуется тол ько при создании объекта.
Теперь, когда объект X M L H t t p R e q u e s t готов, нужно задать функцию обработки запроса и затем создать сам запрос. __ Э т а ф у н кц и я вы зы вает ся после о т в е т а сервера на запрос.
request.onreadystatechange = handler; request.open(type, url, true); // всегда асинхронный (true) , чт ы й за п р о с г о т о в к о т п р а в к е , здесь ж е у к а зы в а е т с я его т и п (Q E T или POST).
При открытии запроса следует указывать его тип ("GET" или "POST"), адрес U R L сервера, а также является ли этот запрос асинхронным или нет. Асинхронные запросы выполняются в фоновом режиме, не застав ляя сценарий ждать, именно поэтому почти все запросы Ajax являются асинхронными. далее *
565
все получено
Получение U отправка Тип запроса Ajax крайне важен, поскольку отражает не только содержимое запроса, но также и его назначе ние. Первый тип, его еще принято называть методом запроса, называется GET и применяется для получения данных с сервера, не влияя на них. Второй тип запро са, POST, обычно связан с отправкой данных на сервер, что приводит к некоторому изменению его состояния.
В Ajax используются те же два типа запросов, которые применяются для отправления HTML-форм, то есть GET и POST.
GET
Используется для получения д а т ы х и не меняет ничего на сервере. Н е большие фрагменты данных могут быть при необходимости отправлены на сервер в виде URL. Запрос GET пре красно подходит для получения запи сей блога из хранящегося на сервере X M L -файла.
PO ST
изменени^’^вдпрТм^ инициируя ных в базу. Ппи “ хранение данданных в ответ на °™Равка идеально подходит Запрос Pos Т записей в блог при п н о в ы х ■^ог при помощи веб-формы.
Запрос PO ST
З а п р о с GET
Date: 0 9 / 2 6 / 2 0 0 8 Body: "These d r e a m s just. I m a g e : c u b e a p a r t .p n g
Имя XM L'айла, с о 'ержащ &го з а т е и блога.
Запрос ^5ET н и к а к не в л и яе т на сервер,, т ак как он всего лиш ь просит прислат ь за п и си .
blog.xml О тв ет н а з а п р о с GET.
566
глава 12
Запрос POST меняет состояние сервера т ребуя сохранит ь
новую запись.
О тв ет н а з а п р о с PO ST.
N
Новая за п и сь в блог, к о т о р у ю
нужно сохранит ь
1на сервере.
динамические данные
Запрос с объектом XMLHttpRequest Определившись с типом запроса и указав этот тип в момент открытия, м ы подходим к задаче отправки запроса на сервер для последующей обработки. Код отправки запроса зависит от того, какой тип вы выбра ли, GET или POST. Тип d E T и URL указы ваю т ся о м о м ен т от кры т ия запроса. request.open("GET",
"blog.xml",
true);
//
всегда
асинхронный
Если а р гум ен т мет ода
Записи блога в формате XML запрошены из располо женного на сервере файла blog.xml при помощи запро
5епсі() и м еет значение
са GET.
request.send(null);
пиИ, значит , о т п р а в ленный запрос не содер жит данных.
/Ш
Е
З а п р о с GET
Ь
Новая запись в блог от правляется на сервер при помощи запроса POST.
При от кры т ии запроса указы вает ся его т и п POST и URL сервера.
Запрос вклн>чает Нй сервер данные, поэт ом у нужно указывать их тип. request.open("POST",
(true)
"addblogentry.php",
true);
//
всегда
асинхронный
(true)
r e q u e s t .s e t R e q u e s t H e a d e r (" C o n t e n t - T y p e " , " a p p l i c a t i o n / x - w w w - f o r m - u r l e n c o d e d ;
c h a r s e t = U T F - 8 " );
request.send("09/26/2008&These dreams just..,&cubeapart.png");
Н е волнуйтесь, если вы пока н е поняли разницу м еж ду запросами GET и POST,
Отправляемые вм ест е с запро сом данные передаются методу 5епс1() в качестве аргумента.
Все станет намного понятнее по мере того, как м ы используем полученные знания на практике для обновления нашего блога YouCube. далее >
567
болезни роста: упрощаем ajax
Упростим задачу Объект XMLHttpRequest является крайне м о щ н ы м инструментом, но пользоваться им непросто, в чем вы уже успели убедиться. Впро чем, требуется и изрядное количество «стандартного» кода, который применяется в любом Ajax-приложении. Поэтому для облегчения работы с объектом XMLHttpRequest пишутся сторонние библиотеки Многие из них расширяют функции JavaScript, что требует изучения дополнительного материала.
Специальный объект A^axRequest упростит создание А^ах-запросов.
Упростив задачу до предела, создадим для нашего блога YouCube специальный объект, который поможет работать с объектом XMLHttpRequest. Это даст нам возможность сфокусировать вни мание на технологии Ajax, вместо того чтобы бороться с объектом XMLHttpRequest или настраивать стороннюю библиотеку. Н а ш объект Aj axRequest сделает работу с объектом XMLHttpRequest намного проще. е>ольилинство методов объект а AjaxRequ&st являю т ся свойст ваMU дост упа к объект у XMLHttpRequest.
XMLHttpRequest
\ '
Л е ж а щ и й в о с н о в е о б ъ е кт X M L H ttp R e q u e s t х р а н и т с я в св о й ств е re q u e s t с п е ц и а л ь н о го о б ъ е кта A ja x R e q u e s t.
Конструктор объекта Aj axRequest крайне упрощен, по срав нению с конструктором объекта XMLHttpRequest. Вот как про сто выглядит код создания объекта Aj axRequest, способного инициировать запросы Ajax во всех современных браузерах;
var
568
ajaxReq
глава 12
=
new
A j a x R e q u e s t ()
_М ет од 5епс(0 объект а AjaкRecшest вы полняет ОСЮ работ у по от кры т ию и от правке запросов.
К о нст рукт ор AjaxRequest авт ом ат ически берет на себя все сложности соз дания базового объекта XM LH ttpRequest.
динамические данные
Магниты JavaScript Специальный объект Aj axRequest является оболочкой стандартного объекта XMLHttpRequest, предоставляя более простой интерфейс для отправки Ajaxзапросов и обработки ответов на них. Но в методе send () этого объекта не хватает ряда фрагментов. Воспользуйтесь магнитами, чтобы восстановить код метода.
.
if
u
n
c
t
i
o
n
,
p
o
.
t
O
a
„
T
,
p
,
,
P = .t .« a ,
,
( t h i s .r e q u e s t != null) { // У д а л е н и е п р е д ы д у щ е г о з а п р о с а t h i s .r e q u e s t .a b o r t () ; // д о б а в и м п а р а м е т р durrmy д л я п е р е п и с ы в а н и я к э ш а бр а у з е р а url += "?du m m y = "
try
+ n e w Date (). g e t T i m e О ;
{
t h i s . r e q u e s t . o n r e a d y s t a t e c h a n g e = ................. t r u e ) ; // в с е г д а а с и н х р о н н ы й
(true)
this .r e q u e s t .o p e n (............ '........... ' if
( t y p e .t o L o w e r C a s e 0 = = "get ) { // О т п р а в к а з а п р о с а GET; без д а н н ы х t h i s .r e q u e s t .s e n d (.
^ / / ' L i p a B K a з а п р о с а POST;
.) ;
п о с л е д н и й а р г у м е н т с о д е р ж и т д а нные
t h i s .r e q u e s t .s e t R e q u e s t H e a d e r (" C o n t e n t - T y p e " , ...................
);
this .r e q u e s t .s e n d ( .................. ' '
} } c a t c h (e) { . f the s erver \n" + "Details: a l e r t ( " A j a x e r r o r c o m m u n i c a t i n g w i t h the server. \
e)
}
handler
ty p e
postDataType
PostData
далее >
569
реш ение задачи с магнитами
//
,сз
Решение задачи с магнитами Вот как выглядит метод send () объекта Aj axRequest.
М е т о д sendQ о т п р а в л я е т за п р о с ы с у к а з а н н ы м на ~ оором аргум ент ов. AjaxRequest.prototype.send= if
fun c tion(type,
url,
handler,
postDat a T y p e ,
postData)
(
( t h i s .r e q u e s t != null) { // У д а л е н и е п р е д ы д у щ е г о з а п р о са t h i s .r e q u e s t .a b o r t (); им у//I Дf о б а вJ—
пара --м е т ір d u m m y•• д л я п е р е п и с ы в а н и я к э ш а б р а у з е р а
url += "?du m m y = "
try t h i s .r e q u e s t .o n r e a d y s t a t e c h a n g e t h i s .r e q u e s t .open.(. if
[
handler
і
true);
type
( t y p e .t o L o w e r C a s e () — "get") { ^ // О т п р а в к а з а п р о с а GET; нет д а н н ы х t h i s .r e q u e s t .s e n d ( pi"I 11
ф у н кц и я h a n d le r вы зы вает ся для об р а б о т ки о т в е т о в сервера.
+ n e w D a t e ()- g e t T i m e ();
II • О т п р а в к а з а п р о с а POST;
11
всегда асинхронный
Л р г ц м е н т ty p e м е т о д а sendQ о п р е д е л яе т , б у д е т ли э т о за п р о с Q E T или P O S T
п о с л е д н и й а р г у м е н т с о д е р ж и т д анные
postDataType t h i s .r e q u e s t .s e t R e q u e s t H e a d e r ( " C o n t e n t - T y p e " ,
Данные о т сы ~ лаю т ся " на сервер т о л ь ко в случае за п р о са т и п а POST.
t h i s .r e q u e s t .s e n d (
PostData
глава 12
);
);
a l e r t ( " A j a x e r r o r c o m m u n i c a t i n g w i t h the s e r v e r . \ n
+
Details.
Э т о т ко д х р а н и т с я oo в н е ш н е м ф айле a ja x.js вмест е с к о н с т р у к т о р о м и другим и м ет одам и о б ъ е к т а A ja xR e q u e st.
570
(true)
+ e) ;
ajax.js
динамические данные
Анализ запросов Ajax Специальный объект Aj axRequest состоит из конструктора и набора методов, один из которых нам особенно полезен. Это метод send (), подготавливающий и отправляющий на сервер запросы Ajax. Все эти запросы принадлежат или к типу GET или к типу POST, аналогично запросам отправки форм в HTML. Но в случае с Ajax запросы не сопровождаются полной перезагруз кой страницы.
AjaxRequest
send(type, url, handler, postDataType, postData)
type Тип запроса, G E T или POST,
handler url
Функция обратного вы зова, используемая для обработки ответов.
Адрес U R L сервера (в случае с блогом YouCube это blog.xml). П р и необходимости данные пакуются в этот URL.
postData
postDataType Тип отправляемых данных (толь ко для запросов типа POST).
Отправляемые данные (только для запросов типа POST). Эти данные можно отправлять в различных форматах.
Все запросы Ajax имеют одинаковую структуру, хотя у за просов типа GET отсутствует два последних аргумента. Соответственно, самыми важными для самых простых запросов Ajax являются первые три аргумента метода send (). В качестве примера рассмотрим запрос данных X M L из находящегося на сервере файла movies.xml: URL запрашиваемо^Tun за проса.
Л
ajaxReq.sendC'GET",
ф айла.
"movies.xml " , handleRequest);
П редп о л а гае т ся, ч т о об ъ е кт А ]а кЯ щ и е ^Ь у ж е создан и х р а н и т с я в переменной a ja x R e q .
Н е волнуй тесь об обработке запросов.
Пока вам достаточно понимать, что существует специальная функция, вызываемая после получения ответа на запрос.
Эта ф у н кц и я б у дет вы зы ват ься для о б р а б о т ки о т в е т а Нй запрос.
далее ►
571
м огу ли я сделат ь запрос?
Выполнение запросов Пока метод send {) отправляет запрос на сервер, веб-страница может выполнять другие операции. Именно поэтому запрос на зывается асинхронным. Пр и синхронном запросе происходит «заморозка» страницы. В ы ничего не можете делать до получения ответа с сервера.
У о и С о Ь е - - П и Ш о д f o r C u b e P o K ie r s
П о к а з а п р о с о бр аб аты в а ется с ер в ер о м , с тр а н и ц а м о ж б т в ы п о л н я т ь д ру*’*'*®
Сервер
д ей ств и я -
^^youcujte.html
Тот факт, что страница не замораживается в процессе обра ботки запроса, не означает, что пользователь действительно может сделать что-нибудь продуктивное. Все зависит от осо бенностей страницы. В случае с блогом YouCube успешный просмотр записей целиком зависит от скорости получения ответа на запрос А^ах.
Асинхронные запросы Ajax не замораживают странипу во время своей обработки.
А КЛ Ю Ч Е В Ы Е М О М Е Н ТЫ
и
Объект XMLHttpRequest является стэндартным и предназначен для обработки запросов Ajax.
Все запросы Ajax делятся на два типа, get и post, и определяются отправляемыми на сервер данными.
Специальный объект Aj axRequest позволяет
работать с Ajax, избегая непосредственных обраще ний к объекту XMLHttpRequest.
572
глава 12
Метод send () объекта Aj axRequest открывает запросы Ajax и отправляет их на сервер.
часаро
динамические данные
ЧаДаБаеМые B o lIp o C b i Обязателен ли для выполнения запросов объект A j a x R e q u e s t ?
может быть и не связан с доставкой HTML-данных. Более того, основным достоинством Ajax является именно возможность запросить данные любого
Q ; Нет. Для отправки запросов и обработки ответов можно воспользоваться непосредственно
типа.
объектом X M L H t t p R e q u e s t . Но зачем это делать, если использовать объект A j a x R e q u e s t удобнее и проще? Он создается для удобства и упрощает работу с Ajax, взяв на себя всю сложную работу по формированию запросов. 3 * Чем запросы/ответы на них Ajax отличаются от запросов/ответов в HTTP? ; Запросы HTTP и ответы на них используются браузерами для получения HTML-страниц с веб-серверов. Запросы Ajax во многом с ними сходны. Вот их основные различия: запрос Ajax
Важную роль таюке играет размер запрашиваемых данных. Ajax вовсе не обязан запрашивать за один раз целую страницу или документ. Вполне можно ограничиться пересылкой фрагмента данных. Именно благодаря этому Ajax позволяет динамически редактировать страницы. При этом вставка новой информации происходит без перезагрузки. ^ 5 То есть Ajax позволяет динамически разобрать страницу по кусочкам?
в реальном времени, не прерывая использования страницы. Другими словами, пользователю не приходится перезагружать страницу для обновления ее небольшого фрагмента. Подгрузка этого фрагмента происходит в фоновом режиме. Каким образом со всем этим связаны запросы G E T и P O S T ?
; Тип G E T или P O S T определяет особенность обработки запроса на сервере. Однако способность время от времени динамически запрашивать данные не зависит от типа запроса. Основное различие между запросами G E T и P O S T в том, меняется или нет
состояние сервера в ответ на получение новых данных. Скажем, если данные сохраняются в базе, их отправка
Q ; Да! При этом важна не только сама способность собирать страницу из фрагментов. Важно распределение во времени этой сборки. Запросы Ajax
типа P O S T . В противном случае можно
и обработка ответов на них происходит
ограничиться запросом типа G E T .
осуществляется при помощи запроса
КТ9 И НТСовместите фрагменты кода с описанием.
XMLHttpRequest
Запрашивает данные, ничего не меняя на сервере.
GET
Отправляет запрос на сервер и получает ответ.
s e n d ()
Отправляет данные на сервер, меняя его состояние.
A jaxRequest
Стандартный объект JavaScript для работы с А^ах.
POST
Специальный объект для упро щения работы с Ajax. далее ►
573
от вет на задачу
Вот какое описание соответствует каждому из фрагментов кода.
XMLHttpRequest
Запрашивает данные, ничего не меняя на сервере.
GET
Отправляет запрос на сервер и получает ответ.
send()
Отправляет данные на сервер, меняя его состояние.
AjaxRequest
Стандартный объект JavaScript для работы с Ajax.
POST
Специальный объект для упрош,ения работы с Ajax.
AjaxR equest X M U H ttp R e q u e b t
----------------
упрощая работу С Ajax.
574
глава 12
динамические данные
Создание запросов Вне зависимости от того, каким образом используется Ajax и к каким данным он пытается получить доступ, обмен данными начинается с за проса. Поэтому первая задача, которую нужно решить Руби для нревраш;ения блога YouCube в приложение, управляемое данными, — это запросить файл X M L с записями блога.
Кажется, мне нужно создать объ ект /AjaxRequest, а затем запросить записи блога.
Создание объекта. AjaxRequest.
Запрос GET для получения с сервера файла blog.xml. Обработка запроса? По поводу ш ага 3 Руби п о к а не -- уверена,, п о э т о м у она р е ш а е т с ф о ку с и р о в а т ь с я на первы х двух э т а п а х -
далее ►
575
реш ение упражнения
„^В озьм и В руку карандаш Решение
Вот как выглядит код создания объекта A j a x R e q u e s t и со ответствующий запрос записей блога.
v a r oj'axRefj = n e w A ja xR e q u e stQ ; © Н а м п о т р е б у е т - ___ СЯ за п р о с G E T для п о лучени я данны х с сервера. ^
a ja xR e q .se n d ("Q E T "j ‘'b lo g .x m l“ , h a n d le R e q u e st); . j Ф айл ф о р м а т а X M L у к а з а н , к а к U R L за п р о с а ^
Д л я о ё р а д о т ки з а п р о сй н а м п о т р е б у е т с я специальная ф у н кц и я h andleR equestQ .
Закончишь — Вызови меня
Сценарий на стороне клиента После отправки запроса Ajax роль браузера меняется — он не ждет ответа с сервера. Благодаря тому, что запросы Ajax обрабатывает ответ, полученный обычно являются асинхронными, пользователь может продолжить работу со страницей, а ожидание ответа проис на запрос Ajax, при помопщ ходит в фоновом режиме. Как только обработка запроса на специальной функции обратного сервере закончена, ответ обрабатывается кодом JavaScript при помощи функции обратного вызова. вызова. Сервер о т п р а в л я е т о т в е т б р а у зе р у , к о т о р ы й вы зы вает с п е ц и а л ь н у ю ф у н к ц и ю о бработ ки.
Создание объекта A j a x R e q u e s t . @
Занре€-€&¥-йДя-нодучения -с-сеушера файла hlo^ptwU(^ ^ ^ б р а б о т к а
576
глава 12
handleRequestО ; В сценарии блога до л ж н а присут ст воват ь ф у н к ция о б р а т н о го вызова n a n d le R e q u e s t ( ) .
динамические данные
Обработка ответа в нашем случае окончание обработки запроса должно приводить к вызову специальной функции handleRequest (), которая в за висимости от полученных с сервера данных предпринимает опреде ленные действия. Каким же образом функция, об рабатывающая ответ на запрос, получает доступ к присланным с сервера данным?
Доступ к полученным в ответ на запрос данным имеют методы объекта AjaxRequest. Для этой цели применяется два метода объекта Aj axRequest, которые называются getResponseText {) и getResponseXML ().
A jaxRequest
getResponseText() Получение ответа на за прос Ajax в виде текста. g e t R e sponseXML() Выбор метода зависит от того, в каком формате вам нужно получить ответ. Для получения структурированного кода используйте метод getResponseXML (). Соответственно, метод getResponseText () даст ответ в виде обычного текста.
Получение ответа на запрос Ajax в виде структурированного X M L -кода.
Ш ТУРМ Код X M L во многом н апом и нает код H T M L . Как бы вы орга низовали доступ обработчика запросов к данны м X M L ?
далее > ■
577
на помощ ь приходит DOM
Если XM L является набором тегов, нельзя ли для обработки таких данных использовать DOM?
DOM как Выход из поло)кения Любовь Руби к сісладьіванию головоломок явно развивает ло гическое мышление, потому что она совершенно права, пред лагая воспользоваться D O M для обработки данных в формате XML. Как вы помните, D O M управляет данными HTML, пред ставляя их в виде дерева узлов. А значит, аналогично можно поступить с данными XML. Достаточно представить как дерево узлов блог YouCube. ^<tltle>YouCube - The Blog for Cube Puzzlers</title> <author>Puz2ler Ruby</authot> <entries> <entry> <date>08/14/2008</date> ^ <body>Got the new cube I ordered. It's a real pearl.
.
</entry> <entry> <date>09/26/2008</date> <body>These dreams just keep getting weirder... a cube take itself apart. What <strong>does</strong> it mean?</body> <image>cubeapart.png</image> </entry> </blog>
author
"Puzzler Ruby
Тег <Ьое(у> м о ж е т бы т ь п р е д к о м для целого н а бора т егов, если за п и си ~ блога с о д е р ж а т НТМЬфюр м а т и р о в а н и е .
..... Тег <аиИаог> с о д е р ж и т и м я а в т о р а в виде д о чернего т е кст о в о го эл е м е н т а .
578
глава 12
Руби нужно извлечь записи блога из набора узлов XML, что прош;е всего сделать при помош,и функции. Нет смысла добавлять к блогу YouCube дублируюш;иеся фрагменты кода, если этого можно избежать.
динамические данные
Q «функции get]e^t() Подробно Специальная функция getText () выполняет монотонную ра боту по извлечению содержимого узлов DO M . function getText(elem) Э т от аргум ент ука~ . зы ва е т на э л е м е н т , содерж им ое кот орого т р е б у е т с я извлечь.
var text = if
(elem) if
{
(elem.childNodes) for
(var 1 = 0 ;
Ц иклический просм от р всех дочерних узлов эл е м е н т а .
{
i < elem.childNodes.length; i++)
{
var child = elem.childNodes[i]; if
(child.nodeValue) text += c hild.nodeValue;
else {
^ _______________
if (child.childNodes) if
Д обавление содерж им ого дочерних узл о в в перем енную te x t.
(child.childNodes[0].nodeValue) text += child.childNodes[0].nodeValue;
return text;
в руку карандаш
В о зв р а щ а е м . п е р е м е н н у ю te x t , в кот орой т е п е р ь н а хо ди т ся все с о д е р ж и м о е дочерних узлов.
Если дочерние узл ы , в свою очередь, я о л я ■ю т с я п р е д к а м и для др у г и х узл о в, б ерем т е кс т о в о е со де р ж и м о е первого из них и двигаем ся дальше.
П р е д п о л о ж и м , ч т о п о л у ч е н н ы е в о т в е т на з а п р о с д а н н ы е в ф орм ате X M L уж е со хр ан е н ы в пе р е м е н н ую
xmlData. Н а п и
ш и те код, з а д а ю щ и й с и г н а т у р у б л о га Y o u C u b e к а к с о д е р ж и м о е X M L -тега
<author>.
далее V
579
ответы на запросы о себе
Вот как выглядит код, задающий сигнатуру блога YouCube как содержимое XML-тега <author>.
‘'«t-riM я \^^'^/< ^J< aK ^cu zH ai'vvwM M yp a м я вилляяеемт сся сб о й ст в о м у р о вн я к л а сса , ее з а дание до л ж н о рсущ есилвлят ься п р и п о м о щ и п р о т о т и п а Blog.
В спом огат ельная ф у н кц и я y e tT e x tQ и зв л е к а е т с о д е р ж и м о е т ега < a u th o r> .
В Х М и -д а н н ы х м о ж е т бы т ь т о л ь к о один т ег <аиЬког>_, п о э т о м у п р о с т о дерем п е р вы й тег.
^ ^ Q B P A S O T IC A . еУ Ш Ё Т еЗВ Й Л
Э А П Р С (С Ы
И нтервью нед ел и: И с п о в е д ь ф у н к ц и и h a n d le R e q u e s t O
Head First: М ы слышали, что вы достигли совер шенства в ответах на запросы Ajax. Расскажите, что для этого нужно?
handleRequestO: Это решаю не я. Я же специаль ная функция и меняюсь от приложения к прило жению.
handleRequestO: Когда приходит ответ на за прос, я его обрабатываю. Сначала нужно убе диться, что ответ корректен, затем я перехожу к полученным данным и при необходимости интегрирую их в веб-страницу.
Head First: Почему?
Head First: То есть вас вызывают сразу после за вершения запроса? handleRequestO: Да. Хотя на самом деле меня не сколько раз вызывают и в процессе обработки за проса, но по большей части в моих услугах люди заинтересованы только в самом конце. Head First: И как же вы узнаете о том, что насту пил тот самый момент? handleRequestO: Ну, объект AjaxRequest имеет пару методов, при помощи которых я могу про верить состояние запроса и убедиться в том, что его обработка без проблем завершена. Head First: А откуда вы узнаете, что нужно делать в этот момент?
580
глава 12
handleRequestO: Потому что разные приложе ния используют полученные в ответ на запрос данные по-разному. Head First: В ы хотите сказать, что для каждого приложения вас нужно писать заново? handleRequestO: Именно так. И это имеет смысл, ведь, к примеру, приложение для покупок в Интернете обрабатывает Ajax-запросы совсем не так, как блог. Ajax гарантирует мой вызов по сле завершения обработки запроса, а дальше все зависит от приложения. Head First: То есть создание управляемой Ajax страницы означает создание специального обра ботчика запросов? handleRequestO: Да, вы все правильно поняли. Head First; Спасибо за поучительную беседу. handleRequestO: Всегда счастлива поговорить.
динамические данные
М Ш А ПОМЯ ГАМТА П о п р о б у й т е с е ^ я Б р>оДи сосв д аБ и в д е Л я
n jn iM e ^ a H u u U og-bffC H um e, к а к j^ a S o m a e m =ф у н к ц и я W i J I e R e ' ^ s t O 1 -
iu n c tio iL
М аГиЧ есКое Ч исло. Ц айД ехпе
Л и Б ь 1 'J oC ogpH H ooxieU , В е д у щ и х к y<3iemHo]viy Б ь л о л н е н и р э з а п р о с а ?
function if
handleRequestO
{
(ajaxReq.getReadyStateО 11
Сохраняем
var
//
xmlData
Задаем
полученные =
//
сигнатуру
Создаем массив entries
for
(var
//
=
a j a x R e q . g e t S t a t u s () формате
==
200)
{
XML
блога =
объектов
"by
"
Blog,
+
g e t T e x t ( x m l D a t a .g e t E l e m e n t s B y T a g N a m e ( " a u t h o r " ) [0])
содержащий
отдельные
записи
i <
e n t r i e s .l e n g t h ;
i ++)
{
запись
blog.push(new new
&&
в
xmlData.getElementsByTagName("entry");
1 = 0 ;
Создаем
4
a j a x R e q .g e t R e s p o n s e X M L ( ).g e t E l e m e n t s B y T a g N a m e ( " b l o g " ) [ О ];
Blog.prototype.signature
var
==
данные
B l o g ( g e t T e x t ( e n t r i e s [ i ] .g e t E l e m e n t s B y T a g N a m e ( " b o d y " ) [0]),
D a t e ( g e t T e x t ( e n t r i e s [ i ] .g e t E l e m e n t s B y T a g N a m e ( " d a t e " ) [ 0])),
g e t T e x t ( e n t r i e s [ i ] . g e t E l e m e n t s B y T a g N a m e ( " i m a g e " ) [0])));
} //
Отображаем
блог
s h o w B l o g (5) ;
далее >
581
ответ на задачу
О т в е т на
з а д а ч у
I j o r n к а к и м и К о м м е н т а р и я м и сЛ е Д °Б а Л о
снабдить сзаеДиаЛьнук* =рункДи1о Wicllej|e=ji'est().
Убеждаемся в успеш ном выполнении запроса Ajax, проверяя его состояние. '
Присваиваем сигнат уре блога содержимое т ега <autkor>. function if
handleRequestO
{
(ajaxReq.getReadyStateО //
Сохраняем
var //
xmlData Задаем
полученные =
//
сигнатуру
Создаем entries
for
(var
/ /
массив =
i =
Создаем
4
&& в
ajaxReq.getStatusО формате
==
2 00)
{
XML
блога =
объектов
"by
"
Blog,
+ g e t T e x t ( x m l D a t a .g e t E l e m e n t s B y T a g N a m e (" a u t h o r " )
содержащий
отдельные
записи
[ Oi :
ПолучаеМ все
x m l D a t a . g e t E l e m e n t s B y T a g N a m e ( " e n t r y " ) ; ^ — — --------- э л е м е н т ы , с о 0;
i <
e n t r i e s .l e n g t h ;
i ++)
^^рж ащ ие за -
{
писи
запись
blog.push(new new
==
данные
а j a x R e q . g e t R e s p o n s e X M L ().g e t E l e m e n t s B y T a g N a m e ( " b l o g " )
Blog.prototype.signature
var
X M L -данные содержат всего один т ег <Ыоу>, поэт ом у берем первый элем ент массива, во з вращенного функцией yetE lem entsByTagN am eQ .
бл ога .
B l o g ( g e t T e x t ( e n t r i e s [i ] .g e t E l e m e n t s B y T a g N a m e (" b o d y " ) [ 0 ] ) ,
D a t e ( g e t T e x t ( e n t r i e s [ i ] . g e t E l e m e n t s B y T a g N a m e ( " d a t e " ) [0]
g e t T e x t ( e n t r i e s [ i ] . g e t E l e m e n t s B y T a g N a m e ( " i m a g e " ) [0])));
//
Отображаем
блог
s h o w B l o g (5);
Вызываем ф ункцию 5кошВ1од() для отображения на ст ранице пят и последних записей.
Создаем новый объект Ыод для очередной записи и добавляем т уда последний элем ент м а с сива при помощ и мет ода pushQ объект а Array.
О Сделано!
582
глава 12
динамические данные
YouCube, управляемый данными
---------- — -— ~_Г7ослеЗняя версия ф а й лоб YouCube дост упна
\СРуби восхищена новым обликом, который ее блог приобрел благодаря Ajax (это сэкономило ей много времени), но она обеспокоена тем, что происходит на странице в процессе загрузки данных
для скачивания по адресу h ttp ://w w w M e a d fin tla b s. com /books/hfjs./.
r Теперь, когда записи выделены
<Ыод> <author>
в ХМЬ-код, блог работает просто здо рово, но как дать понять пользователям, <dat*>08/29/200«</.
что идет процесс загрузки?
<body>FounO а 7к-7х7 <«ntry> <date>OB/?9/JOOS</da <bo<ly>M«t up with SOI
о prepare.</body>
__...ль.,:*.«««':*“'»"'« У ш С и Ь с -ТЬс Ш о « tor С»Ье Т т
<tt»t«>09/S/200e</(Jate>
Ла
<«ntry> «lae«>0S/i9/2O0e</date> <lme9e>cube777.pn,</imige> </entry> <*ntry> <det»>09/24/2008</dAte> <bedy>I dre,™d last night a
шшч»
■»».Л»»*»t“Pе““«
ЫРиакгЫу
_
^ ШI iJjoaied 4Дв08 _ ^ last meht в
iffРаЫ егRuby
Теперь блог управляет ся дан ными XML...
Щ
c
h
e
s
m
s
«"У
'
ЬуРиикгИчЬу S S * « = W 7.7.7 » « , С о . « Ы « у И Ь Ь * , о . Г « . « И . . .
byPiuxterRniry
...но некот орых пользоват елей см ущ ает пуст ая ст рани ц а . кот орая появляет ся в п р о цессе загрузки данных.
Возьми в руку карандаш
Впишите в функцию lo a d B lo g ( ) отсутствующую строчку кода, которая отвечает за отображение картинки wait.gif, демонстрируемой в процессе загрузки записей. Подсказка: используйте основной тег function
loadBlogо
d iv
блога с Ю
"Ы о д ".
{
ajaxReq.send("GET",
"blog.xml",
handleRequest);
далее *
583
реш ение упражнения
Возьми В руку карандаш Решение function loadBlogо
Вот как выглядит код функции loadBlog ().
{
.7. ajaxReq.sendC'GET",
"blog.xml", handleRequest);
И з о б р а ж е н и е дем онст рирует ся ö процессе з а г р у з к и записей блога.
}
Анимированное изо5ряжение
r
S
src-w a it.g if' a j t - Loading... ' />";
О
YouCub« - The Blog for Cube Puzzlers^
««««»»
Ä
8 данном случае пройде вос пользоват ься свойст вом innerH TM L, чем DOM, пот ом у чт о т ег image добавляется к паре ат рибут ов.
VuCub. - The Blog tor C b e P « » * »
пользобйжелям. ч т о идет за грузка даннш . N
Hioioc 001 aic
X X
N Search the Biog
|j
wait.gif S h o w All Bofl Entries |
_
View a Random Mofl Entry
Ч асщ о
Задаваем ы е :>
J'
Б о ц |= » о с гь 1 Последняя запись блога YouCube содержала тег HTML
'I Как работают свойства
readyState
и
status?
<strong> . Допустимо пи это в коде XML? ! Оба этих свойства принадлежат объекту I Если помните, XML-код применяется для представления данных любого типа. В данном случае, учитывая, что тело записи будет вставлено в веб-страницу, технически возможно
и предназначены для отслеживания со стояния запроса, например (0) означает, что запрос не инициа лизирован, а (4) — что данные загружены, а также его статуса,
включить HTML-теги, влияющие на вид записи после вставки. Другими словами, содержимое каждой записи блога может включать в себя HTML-теги, передаваемые вместе с XML-кодом
например 404 означает (not found), а 200 означает (ОК). Под робное рассмотрение этих свойств в данном случае не требует ся. Вам достаточно знать, что запрос выполнен, если состояние равно 4 (loaded), а статус имеет значение 200 (ОК). Только при
в виде специальных узлов, ответственных за форматирование. Впрочем, это достаточно сложная задача^ ведь нам нужно рекон струировать узлы, которые использовались для форматирования HTIVIL-кода, при вставке в страницу XML-данных. В случае блога YouCube мы решили отделить текст от HTML-тегов, оставив фор матирование за кадром. Но вполне возможно, что в следующей версии YouCube этот аспект будет учтен.
584
глава 12
XMLHttpRequest
этих условиях вызывается функция
handleRequest (),
динамические данные
Неработающие кнопки Хотя внесенные при помощи Ajax изменения не оказали осо бого влияния на внешний вид блога YouCube, кое в чем интер фейс претерпел изменения. Кажется, кнопки на нашей страни це перестали работать нужным нам образом.
Sean h the Biog
- Г
'
Пользователи сообщают, что кнопки не всегда срабатывают. П осле щелчка ниче го не происходит. Более того, сам блог становится невидимым. В чем же дело?
Show А» efoq
Entries О
View а Random Biog Entry |
По непонят ны м причинам кнопки иногда п ер ест а ю т работ ат ь, а блог при эт ом ст ановит ся невидимым.
Неработающие кнопки
=
Разочарованные пользо ватели
Ш ТУРМ П о ка ки м п р и ч и н а м м о гу т н е р а б о т а т ь кн о п ки ? Н а ка ко й с т а д и и з а гр у зки с тр а н и ц ы м о ж е т в о зн и ка ть э та п р о б л е м а ?
Руби не волнует ся, но очень хот ела бы уст ранит ь эт и непо ладки.
далее ►
585
когда я могу этим воспользоваться ?
Кнопкам ну)кны данные Дело в том, что кнопки в нашем блоге работают только при наличии доступа к данным. А так как данные теперь загружаются из внешнего ХМЬ-файла, некоторое время страница суш;ествует без них. В этот период сущ;ествовапие кнопок лишено смысла и только запутывает пользо вателя.
Отключение кнопок — прекрасное решение. Отключив кнопки на время загрузки данных, м ы простым и элегантным способом решим проблему. Ajax отправляет запрос данных при первой загрузке страницы, а значит, кнопки можно изначально отключить, предоставив затем к ним доступ при помощи функции handleRequest (), ко торая запускается после завершения обработки запроса. Отключение реализуется при помощи атрибута disabled тега <input>. Этому тегу присваивается значение "disabled" в НТМЬ-коде. И наоборот, ему можно присво ить значение false в коде JavaScript, включив тем самым кнопку.
<input type="button" value="Search the Blog" S e a rc h th e S lo g
i
disabled="disabled" />
S m r c h th e il o p
buttonElem.disabled =» false;
586
глава 12
динамические данные
Магниты JavaScript В о с п о л ь з у й т е с ь м а г н и т а м и д л я з а п о л н е н и я п р о б е л о в в ко д е с т р а н и ц ы Y o u C u b e . С д е л а й те так, ч т о б ы к н о п к и б ы л и н е д о с т у п н ы д о з а в е р ш е н и я з а г р у з к и за п и се й . Н е к о т о р ы е м а гн и т ы м о ж н о и с п о л ь з о в а т ь н е с к о л ь к о раз.
“ ftl.>Vo„Cub=
- Th e Bio,
£oi е л е
Puz.ler=</tltle>
< s c r i p t type <script type="text/javascript" <script type="text/javascript">
f:.;ction h a n d l e R e q u e ^ O if
(
^
a j a x R e q . g e t S t a t u s () == 200)
{
( a j a x R e q . g e t R e a d y S t a t e и
// В к л ю ч е н и е к н о п о к
) .
document.getElementByld!
) .
d o c u m e n t .g e t E l e m e n t B y l d (_
) .
document.getElementByld(^
} </script> </head>
-e
e .o ..
onclick="searchBlog0 ; "
< i n p u t
”t y p e = " t e x f
id="searchtext"
:?SufSe:C«orid="sbowall"
name-searchtext"
value-"
/>
/>
v a l u e = " S b o w Л11 B l o g E n t . i e . " o n c l i c k = " s h o w B l o g 0 ; " />
<ln;:t;p:i"buln:';l"v;:;a::.m"
value-Vle«
a R a n d o m B l o g Ent.y'^
o n c l i c k = " r a n d o m B l o g {);"
"search"
/>
</ b o d y > </html>
"showall" "viewrandom"
^
| disabled
|
false
1
"disabled"
1
далее *
587
реш ение задачи с магнитами
Решение задачи с магнитами Вот как должен выглядеть код блога YouCube, в котором доступ к кнопкам предоставля ется только после окончания загрузки записей.
<html> <head> <title>YouCube
- T h e B l o g for C u be P u z z l e r s < / t i t l e >
<script type="text/javascript" <script type="text/javascript" ocript
src="ajax.js"> </script> s r c = " d a t e .j s"> < / s c r i p t >
type="text/ javascript">
function h a n d l e R e q u e s t O { if ( a j a x R e q . g e t R e a d y S t a t e 0
== 4 && aj a x R e q . g e t S t a t u s ! )
onn^ =- 200)
// В к л ю ч е н и е к н о п о к d o c u m e n t .g e t E l e m e n t B y l d ( d o c u m e n t .g e t E l e m e n t B y l d ( d o c u m e n t .g e t E l e m e n t B y l d (
) </script> </head> < b o d y o n l o a d = " l o a d B l o g ();"> < h 3 > Y o u C u b e - The B l o g for C u b e P u z z l e r s < / h 3 > < i m g s r c = " c u b e . p n g " a l t = " Y o u C u b e " /> < i n p u t t y p e = " b u t t o n " i d = " s e a r c h " v a l u e = " S e a r c h the Blog"
"disabled"
disabled <input type="text"
id="searchtext"
name="searchtext" value-""
/>
<div i d = " b l o g " x / d i v > , < i n p u t t y p e = " b u t t o n " i d = " s h o w a l l " v a l u e = " S h o w A ll B l o g E n t r i e s
"disabled"
discjsled <input type="button"
disabled </body> </html>
588
глава 12
|.=
i
id="viewrandom"
"disabled"
|
v a l u e = " V i e w a R a n d o m B l o g Entry" o n c l i c k = " r a n d o m B l o g {) ;" />
динамические данные
Функция, экономяи^ая Время Н а данный момент блог YouCube уже управляется динамическими данными, но Руби пока еще рано почивать на лаврах. На странице блога отсутствует интерфейс для добавления записей. А Руби хотела бы не редактировать каждый раз X M L -файл, а писать непосредственно в блог и сохранять результаты на сервер.
Мне надоело редактировать фай лы и отправлять их на сервер по FTP. Я хочу обновлять свой блог YouCube непосредственно в браузере! ■ V
Редактировать код +
Отправлять файлы на сервер
= Надоело!
Руби хотела бы вводить записи в форму непосредственно на странице блога. Хотела бы, чтобы для этого ей было достаточ но браузера и чтобы больше никаких текстовых редакторов и РТР-клиентов.
YouCube - ArfdtaB totht№ o9fofC ubg_gugk«
Уо1;СиЬе Adding to the Blog for Cube Pmriers
Image (optional): Add tht New B o g Entry
]
,
Для добавления новой записи дост аточно заполнит ь фор му и щ елкн ут ь на кнопке!
Страница добавления новой записи содержит т ри поля для т р ек видов данных.
•V
Ш ТУРМ
Каким образом A jax позволяет добавлять записи в ф о рм ате X M L посредством пользовательского интер ф ейса на веб-странице?
далее >
589
и снова клиент и сервер
Запись данных 6 блог Размышляя о записи данных в блог в терминах Ajax, мож но представить запрос типа P O S T , отправляющий их на сервер, где они записываются в файл Ы о д .xml. Ответ сервера в данном случае не требуется.
И как же новая запись попадет в располо женный на сервере файл blog.xml? Насколь ко я помню, JavaScript не умеет записывать файлы.
Да, 1ауа8сг1р1 не п о м о ж е т вам записать д а н н ы е на сервер.
Более того, на стороне сервера вы даже не сможете запустить код JavaScript. Ведь JavaScript — это клиентская технология, разработанная для использования исключительно в браузе рах. Н о нам-то требуется записать файл на сервер. Эта за дача возникает не так уж редко, и поэтому технологии, ис пользуемые на стороне сервера, часто применяются в паре c J a v a S c rip t.
Итак, нам нужна технология, подобная JavaScript, но функ ционирующая при этом на стороне сервера. Есть несколь ко вариантов, из которых м ы выберем наименее сложный и умеющий обрабатывать данные в формате ХМ...
590
глава 12
динамические данные
На помощь приходит РНР Язык написания сценариев Р Н Р — это то, что нам нужно для записи данных в X M L -файл на сервере. Задача включает в себя чтение X M L -файла, добавление новой записи к уже существую щ и м и сохранение новой информации. Впрочем, в результате м ы все равно возвращаемся к получению записей с сервера при помощи Ajax-aanpoca со стороны браузера. Date:
~
это язык РНР написания сценариев, работающий на стороне сервера.
~ —
lo o lc in ,..,.
Новая запись от правляем ся на сервер как данные запроса A jax т ипа POST.
РНР играет т у же роль, чт о и JavaScript, но на ст ороне сервера, а не на ст ороне клиент а.
Сценарий РНР Нй серве ре заносит новую запись блога в ф айл blog.xml.
blog.xml
Р Н Р можно представить как эквивалент JavaScript, работающий на стороне сервера... Именно он поможет сделать запись новых X M L -дапных в блог!
б елее Р
591
на ст ороне сервера
^ o in o B b iÜ К о д
пг
Сценарий Р Н Р на стороне сервера добавляет новую запись в файл blog.xml. ст рочны х данных XML в п е р е м е н н у ю $rawB!og.
<?php $filename if
Проверяем, существует ли нужный файл.
"blog.xml";
(file_exists($filename)) ( // З а г р у з к а з а п и с е й б л о г а из ф а й л а X ML $rawBlog = file_get_con t e n t s ( $ f i l e n a m e ) ;
Если ф айл не сущ ест вует , создаем пуст ой докум ент XML.
} else
{
// Создание пустого XML-документа $ r a w B l o g = "<?xml v e r s i o n = \ " l .0\" e n c o d i n g = \ " u t f - 8 \ " ?>"; $ r a w B l o g .= " < b l o g X t i t l e > Y o u C u b e - T he B l o g for C ube P u zzlers</ title>"; $rawBlog
.=
"<author>Puzzler Ruby</author><entries></entriesX/blog>" ;
$xml = new SimpleXmlElement($rawBlog);
П реобразу ем строчные данные з а п и си в ф о р м а т XMLj к о т о рый во многом напом инает дерево DOM в JavaScript.
// Добавляем новую запись блога как дочернии узел $ e n t r y = $ x m l - > e n t r i e s - > a d d C h i l d (" e n t r y " ); $entry->addChild("date", $entry->addChild("body", if
-- Новая запись ста -
новится дочерним узлом в ст рукт ире данных XML.
$ _ R E Q U E S T [" d a t e " ]); s t r i p s l a s h e s ( $ _ R E Q U E S T [" b o d y " ])
( $ _ R EQUEST["image"] != "") $ e n t r y - > a d d C h i l d ( " i m a g e " , $ _ R E Q U E S T [ " i m a g e " ]);
// Записываем блог в файл $file = f o p e n ( $ f i l e n a m e , ' f w r i t e ($file, $ x m l - > a s X M L ( fclose($file);
?>
С охраняем ф а й л блога после добавления новой записи. addblogentry.php
_
т
Чаапо
^аД аБ аеМ ы е
Сценарий РНР хранит ся в ф айле addblogentry.php.
В о Ц р *о С Ь 1 Обязательно ли использовать РНР для записи файлов на сервер?
3 * Можно ли применять Ajax без не
сервера, является главная страница блога
обходимости использовать программы, работающие на стороне сервера?
YouCube. Но большинство Ajax-приложений далеко не так просты, и без сценариев,
Q j Не обязательно. Существуют и другие технологии написания сценариев, работающих на стороне сервера. Напри мер, Perl (CGI), который умеет делать ровно то же самое, что и РНР. Вы можете по своему желанию выбрать технологию для создания работающего на стороне сервера компонента Ajax-приложения.
592
глава 12
; в некоторых случаях да. Помните, что все запросы Ajax, кроме самых про стых, сводятся к получению сервером дан ных от клиента и последующей обработке этих данных, например поиску информа ции в базе или записи в файл. Хорошим примером запроса Ajax, не требующим выполнения сценариев на стороне
работающих на стороне сервера, уже не обойтись. Вопрос в том,отправляется ли вам в качестве ответа сервера целый файл, как в случае с файлом blog.xml, или же данные требуют более сложной об работки. Впрочем, большинство предназна ченных для этого сценариев крайне просты и не требуют особых знаний по программи рованию на стороне сервера.
динамические данные
Требования РНР в отличие от языка JavaScript, по умолчанию поддерживаемого современными браузерами, далеко не на всех серверах поддер живается РНР. Поэтому перед отправкой на сервер РНР-файлов нужно узнать у системного администратора, насколько это допусти мо. Возможно вам потребуется провести некоторые операции по настройке или поискать другой сервер. Ведь без поддержки Р НР сценарий блога YouCube просто не будет работать.
Для запуска РНРсценариев может потребоваться предварительно настроить сервер.
РНР У б е д и т е с ь , ч т о в а ш с е р -^ вер п о д д е р ж и в а е т
PHF
Если поддержка от сут ст вует, вы можете подключить ее само стоятельно или попросить это сделать администратора.
Затем нужно выбрать место на сервере, где будут храниться ваши РНР-файлы. В большинстве случаев их можно поместить в ту же папку, в которой хранятся НТМЬ-страницы и внешние файлы JavaScript. Н о иногда установки Р Н Р требуют сохранения сценариев в отдельную папку. Узнать это можно у вашего системного администратора.
В большинстве случа ев дост аточно п о м е с т и т ь сценарии РНР в одну папку с вед
addblogentry.php
страницами.
Выбрав место на сервере для ваших РНР-файлов, продолжим работу над усовершенствованием на шего блога YouCube.
youcube.html
blog.xml
ajax.js
далее *
593
особенности использования php
Данные для РНР-сценария Давайте посмотрим, каким образом РНР-сценарий записывает данные в расположенный на сервере X M L -файл. Именно это позволит нам составить запрос Ajax таким образом, чтобы вы полнить поставленную задачу. Сценарию Р Н Р требуется информация о новой записи в блог, состоящая из двух, а может быть, даже трех фрагментов.
Date
Данные передаются РНР-сценарию через запрос i^ax.
^
Дата записи.
Body
Date; 10/04/2008 Body; "I'm really looking..." ■ Image;
Тело записи.
Image Присоединенное изображение.
Клиентский код JavaScript должен преобразоват ь данные о ф о р м а т , пригодный для от правки на сервер в виде запроса Ajax.
Всю эту информацию нужно упаковать и отправить на сервер в виде запроса Ajax. Там он будет обработан и сохранен в файл blog.xml.
\iZ 3j
Сервер п о л уч а ет запрос A jax и передает данные сценарию РНР для обработки.
<entry>
<blog> <author>.. <entries> <entry>
На эт ой с т а дии новая запись уже добавлена о ф айл blog.xml и авт ом ат и чески отобра зит ся в блоге УоиСиЬе после перезагрузки страницы.
594
глава 12
blog.xml
<date>10/04/2008</date> <body>I'm really looking...</body> <imageX/image> </entry>
Сценарий PHP преобразует запись блога в ф о р м а т X M L и сохраняет ее в ф айл blog.xml.
Теперь нужно понять, как должна выглядеть веб-страница, интерфейс которой позволяет выполнять ввод новых записей, а потом собирает информацию и передает ее на сервер при помощи запроса Ajax. К счастью, нам практически ничего не потребуется делать в ответ на запрос, кроме разве что под тверждения об успешном сохранении новой записи.
динамические данные
реш ение упражнения
возьми В руку карандаш 'ешение
Вот к а к вы глядит веб-страница блога YouCube, пред назначен ная для добавления новы х записей.
Данны й запрос A jax от носит ся к т и п у PO ST и сост оит из следую щ их ф р а гм ен тов:
Страница для до~ оавления записи содержит ф орм у с нужными полями.
* Д а т а записи * Тело записи YouCube ~ Addif« to the Шод fof Cubt Poaaiefs .
YouCube - Adding to the Blog for Cube Puidcrs Паю: |l0/04/Z008~_____________________________________ Body: jfm renlly ipoking forward to
f
this puzile paRy al the end of the month
* Изображение (не обязательно) Введенные данные пересы лаю т ся на сервер при помощ и запроса т ипа PO ST
Щ елчок на кнопке A d d приводит к от правке запроса A jax
О т в ет на запрос A jax не возвращ ает никаких данных, т ак как в наш ем случае эт ого не т ребует ся Сервер записы вает новое содержимое олога в виде дан ных ф орм ат а XML о ф айл blog.xml.
596
глава 12
динамические данные
ОшпраВка данных на сервер Запрос POST сложнее запроса GET, так как связан с от правкой данных на сервер. О н поддерживает различ ные способы упаковки информации, но для нас вполне подойдет стандартное кодирование URL. Именно при помощи этой техники браузеры передают на сервер поля данных в адресе U R L веб-страницы. Ее можно от личить по символу (&), используемому для разделения фрагментов данных.
Date: 10/04/2008 Body: "I'm really looking. Image:
щ ш т
у ------------------------"date=10/04/2008&body=I’m really looking forward... simage=" Ф рагмент ы данных "от деляю т ся друг от друга сим волом &■
О т дельны й ф р а гм ент данных сост оит из и м е ни и значения. В этом формате данных все фрагменты состоят из имени и значения, разделенных знаком (=), а каждая пара имя/зна чение отделена знаком (&). Формат называется закодирован ным U R L и имеет свой собственный тип данных, который указывается в запросе Ajax POST.
Это официальный т и п данных закоди - рованного URL, ко торый указывает ся при формировании запроса POST.
"application/x-www-form-urlencoded; charset~UTF-8"
Итак, все готово для написания кода запроса и его отправки на сервер, где данные будут сохранены в файл blog.xml.
Приведите показанные ниже фрагменты данных в формат закодированного URL, под ходящий для создания запроса post.
releaseDate: 01/13/1989 title: Gleaming the Cube
director; Graeme Clifford
далее *
597
удовлетвори свое лю бопы т ст во
Вот как будут вы глядеть ф рагменты данны х в формате закодированного URL, ненке
^юдходящего для создания запроса P O S T .
"решение
releaseDate: 01/13/1989 title: Gleaming the Cube director: Graeme Clifford
C liffo rd "
_
Часщо
^аД аБ аеМ ы е Б оЦ росьі Если сценарий добавления записи в блог не требует данных с сервера в ответ на запое Ajax, зачем нам обрабатывать этот запрос? ! Нам важно узнать, что запрос был успешно завершен. Ведь именно эта информация сигнализирует сценарию, что можно отобразить всплывающее окно с подтверждением добавления новой записи в блог.
Можно ли в сценарии добавления записи использовать еще и запрос GET?
Так как обработка запроса Ajax и сохранение записи занимают некоторое время, что будет при щелчке на кнопке Add до завершения запроса? Q ; Каждый щелчок на кнопке Add отменяет текущий запрос и отправляет новый. Хотя можно представить и преднамеренный двойной щелчок, в интерфейсе имело бы смысл предусмотреть, чтобы эта кнопка становилось недоступной до завершения запроса. То есть код добавления новой
записи должен отключать кнопку Add на время обработки запроса, а затем активировать ее снова. Подобные усовершенствования интерфейса I Технически это возможно. Допустимо приложений JavaScript сделают работу отправлять данные на сервер вместе более интуитивной и простой и, как с запросом G E T , но нужно точно результат, осчастливят пользователей. указывать URL этого запроса. Впрочем, это не проблема — проблема в том, Что происходит с пробелами что запрос GET не предназначен для в данных, форматируемых ситуаций, когда меняется состояние в закодированный URL? сервера. А в случае добавления записи в файл blog.xml определенно можно говорить об изменении состояния. Именно поэтому нужно использовать запрос
являются проблемой, так как Ajax
P O S T , недвусмьюленно указывающий на намерение взаимодействовать с сервером.
обрабатывает данные автоматически и гарантирует корректность формата с точки зрения сервера.
598
глава 12
Q l Пробелы в данном случае не
Всегда ли при передаче данных на сервер к ним нужно добавлять изображение? 0 ; Нет, этого можно не делать. Вполне допустимо отправлять пустые фрагменты данных, у которых после знака равенства в закодированном URL ничего не стоит:
"date=...&Ьоау=...&1таде=" В данном примере содержимое поля с изображением отправляется на сервер, хотя и не содержит данных. Далее начинается работа РНР-сценария на стороне сервера, который достаточно интеллектуален, чтобы увидеть, что в поле ничего не было введено, соответственно, новая запись в блог не сопровождается картинкой.
динамические данные
Возьми S руку карандаш З а к о н ч и т е н а п и с а н и е к о д а ф у н к ц и й a d d B l o g E n t r y () и h a n d l e R e q u e s t () в с ц е н ар и и д о б а в л е н и я записей в блог YouCube.
function
addBlogEntryо
//
Отключение
//
Пересылка
кнопки
новой
{ Add
и
записи
ajaxReq.sendC'POST",
присвоение
блога
в
виде
if
handleRequestO
Включение
//
Подтверждение
alert("The
кнопки
new
Add
и
==
entry
4
&&
очистка
добавления
blog
busy
Ajax
handleRequest,
charset=UTF-8",
{
(ajaxReq.getReadyState0 //
значения
запроса
"addblogentry.php",
"application/x-www-form-urlencoded;
function
статусу
записи
was
a j a x R e q . g e t S t a t u s ()
==
2 00)
{
статуса
в
блог
successfully
added.
далее ►
599
реш ение упражнения
Возьми в руку карандаш Решение
Вот как выглядят функции addBlogEntry {) и handleRequest () из сценария добавления в блог YouCube записей. В процессе сохранения новой з а ' писи кнопка A d d от клю чает ся. 8 ст роке состояния о т о бражается сообщение « b u sy» , чтобы пользоват ель f u n c t i o n a d d B l o g E n t r y () { знал, чт о идет загрузка. //
Отключение
кнопки Add
и
присвоение
статусу
значения
busy
= tru e ;
Сценарий РНР и с пользует ся для ■сохранения з а п и си блога в файле на сервере.
Это
запрос POST. ■
//
Пересылка
новой
записи
блога
в
виде
запроса
------------ ^
Ajax
-------------- ---------------
ajaxReq.sendC'POST",
"addblogentry.php",
"application/x-www-form-urlencoded;
handleRequest,
charset=UTF-8",
-f docum ent.getE iem entB yld("date“).value + “&hody=" + docum ent.getE lem ent3yld("body").value + "&:image=" + docum ent.getElem entByld("im age").value
—•— function if
handleRequestO
{
(ajaxReq.getReadyState 0 //
Включение
кнопки
Сборка данных запро са POST из полей формы date, body и image.
Add
и
==
4
&&
очистка
a j a x R e q .g e t S t a t u s ()
==
200)
{
статуса ^
П роверка
-- ре-зульт ат ов = false; . , ................................ выполнения docum ent.getElem entByldC 'status").innerH TM L ? запроса на ............................................. 'Д'" (^охранение записи. //
Подтверждение
alert("The
new
добавления
blog
entry
записи
was
в
блог
successfully
added.");
Включение кнопки A d d и очистка ст роки сост оя ния указы вает на заверш е ние процедуры сохранения.
600
глава 12
динамические данные
Вести блог легко Руби не может поверить, насколько проще стало обновлять блог. Ведь ей больше не нужно открывать файл, редактировать код и загружать новую версию файла на сервер. Блог теперь не только управляется данными, но дарит вдохновение для новых записей! ввв
Сообщение подтверждает успешное сохранение новой записи.
_ VouCabe-
The new Ы09 entry was suceessfuBy added.
YoaCube - Adding to the Blog for Cubc P u/ders
__________
РакЫо^/гоов Body: p'm realiy looking
at th* m d of th*
Icnage (opto^); ІдЗЗле Newr f g j i s i j '
Динамиче
Руби делает новые записи прям о на ст ранице в браузере.
Пользователь видит, что добавляется новая запись.
ские данные великолепны!
Новая запись по является в блоге
V
^Y ouC ube. YouCube - The И09 fo ' Cube 1>ии 1ег5
в в в ,._ у оаСвЬе - The Blog for Cube РииЛеи
Search ihe Bag '
rm1^1ookingf«ward»tep»*pa«ya<<>»«dofe««ona.. by Pussier Ruby These
ju« keep getting w eM er.,.ow I » seeing a cube ^ e itself ара«. What
doesitirean?
b y P a a k ’-Ruby
9m m m
I dteamed last night a huge cHbe was by P v ^ r Ruby 9/19/200S
j,
„
chastog me, and it kept yelimg my паив backwajds-.Ybm-t
a !іюп* but the new cube Й finally solved!
byPuaJerRuby
далее ►
601
удобст во применения как козырь
А ^ е ш 1л
работу с блогом еще удобнее
Невозможно достичь подлинного мастерства в сборке головоломок без скрупулезного внимания к деталям. Не удивительно, что Руби хочет довести страницу добавления записей до совершенства. Она узнала, что приложения Ajax известны внимательным отношением к мелочам, влияющ^им на удобство работы. И теперь хочет сделать свой блог конкурентоспособным по отноше нию к современным удобным веб-страницам.
Я хочу увеличить Э ф фективность добавления записей,чтобы писать в блог быстрее и чаще.
Дорабатывает ввод данных в блог Так как большинство записей датируются текущим днем. Руби решила сэкономить время, включив автоза полнение первого поля. А раз дата в результате будет вставляться автоматически, фокус ввода имеет смысл переместить на поле для сообщений. Это даст воз можность приступить к набору новой записи сразу же после загрузки страницы. Разумеется, эти изменения не критичны для работы блога, они даже не связаны непо средственно с Ajax, но они позволяют чувствовать себя на странице более комфортно, что идеально отвечает духу Ajax.
Автоматическая подстановка в поле текущей даты.
VouCube * Adding to the Ш09 for Cube Puzzjers
YouCube / Adding to the Blog for Cube Puzzlers
Date|io/11/2008
__________ _ _ _ _ _ _ _
~
Image (optional);| Ф о кус ввода у с т а н о в и м на э т о по л е , чт о б ы рцби
602
глава 12
Add the Mew Biofl Entry |
.............
- I
О
динамические данные
АВтозаполнение полей Если помните, в блоге YouCube используется формат данных ММ/ДД/ГГГГ, значит, именно его нужно ис пользовать для автоматического заполнения поля даты.
Метод Date уже создан, но он свя зан с главной страницей блога YouCube. Можно ли использовать его для допол нительных страниц?
По в т о р н о е использование кода предотвращает его дублирование.
Нам совершенно не нужен повторяюш,ийся код, ко торый придется в случае чего редактировать в раз ных местах страницы, поэтому имеет смысл настро ить совместное использование двумя страницами фрагмента кода, ответственного за форматирование даты.
y jT V P M Каким образом организовать совм естное исполь зование метода S h o r t F o r m a t () разными стр а ницами блога?
далее >
603
импорт и экспорт
Повторяющаяся задача? Совместное использование K O f l a J a v a S c r i p t различными страницами вынуждает нас поместить такой код в отдельный файл или модуль, который затем будет импортироваться на каждую страницу. В ы уже видели, как это делается, на примере объекта A j a x R e q u e s t , храняще гося в файле a ja x .js. Вот как он импортируется: Имя внешнего файла JavaScript присвоено а т р и б ут у src т ега <script>. <script type="text/javascript" src="ajax.js"> </script>
Для импорта кода JavaScript из внешнего файла воспользуемся рке знакомым нам тегом <8спр1>.
Метод s h o r t F o r m a t () объекта D a t e для этой цели поместим в файл datejs, который затем импортируем в каждую страницу блога YouCube.
Date .prototype.shortFormat - f u n c t i o n O
return (this. getMonthO
{
+ 1) + "/" + this.getDate () + "/" + this .getFullYearO;
Ter < s c r i p t > , который м ы использовали для кода Ajax, применим для импорта в страницы блога сценария из файла datejs.
<script type="text/javascript" src="date.js"> </script>
Содержимое ф айла date.js и м п о р т и р ует ся одним т егом <script>. Всегда имеет смысл помещать код многократного использования во внешний файл, импортируя его затем по мере надобности.
604
глава 12
Д о хр а н и в ко д J a v a S c rip t во внеш нем файле,, м ы п о л ц иаеум в о з м о ж н о с т ь и с -
динамические данные
.
youCu^-Ts»»oafof be
.
Y ooC uJ». The Blog for Cube Ihtucim
ffio^ jf
"■
10МЯ1008
t ot es' “
Г"
byPiKiierRuby
ш лт Miwoee W w jt took me a а ш й butfte nc* cube is ruMlly soh-ed:
нд странице (Подавления новых записей.
Q0 Y o u C u b e - A d d i n g t o I h c B lo g f o r C u b e P u i d c r s
im age (optional): Г A d d t h e N w S t e 9 £ n g ! Lj
возьми в руку карандаш Напишите код функции i n i t F o r m ( ) , вызываемой обработчиком события o n l o a d в сценарии добавления записей в блог. Функция должна вставлять в первое поле текущую дату и устанавливать фокус ввода на втором поле.
далее >
605
реш ение упражнения
Возьми в руку карандаш 'ешение
Вот как выглядит функция initForm ( ) , осуществляющая автозаполнение поля date и установку фокуса ввода на поле body.
в поле date появляется
текущая дата.
Date()).shortFormat(); Г
Ф о кус ввода у с т а навливает ся на поле body.
document.getElementByldC'body").Focus(); }
Сразу после загрузки страницы фокус ввода устанавливается на поле body.
Увеличение продуктивности Наконец-то Руби довольна тем, как работает ее блог YouCube. Благодаря Ajax он управляется данными, имеет дружелюбный интерфейс и внимателен к деталям, которые может оценить только настоящий фанат головоломок.
Adding to
После открытия страницы в поле date автоматически появляется текущая дата. th e В % fo r
Cube Р и г г 1 е ^ “
Oaie:fio7i?l5o08
З Ш
.
Y o u C u b e -T h e
Search theBog
flnaily flnistad wfflkiog OB tl» blog scnpti
byPaakrRuh rm ^ ^ ^ look m g foiward xo this puzitle paity at «ic end o f 4 » mon*. by PuzxUr Ruby
9№ Ю Ш
by Pmder Ruby Done
606
глава 12
T h « (teams just keep geniiig weWer...now I'm seeingacube take itself apart, Whal lioesitraean?