- •Введение
- •Несколько слов о книге
- •Глава 1. Каким должен бытъ Web-интерфейс
- •Действия пользователя при работе с приложением
- •Накладные расходы при работе в сети
- •Асинхронное взаимодействие
- •Независимый и переходный образы использования
- •Четыре основных принципа Ajax
- •Браузер имеет дело с приложением, а не с содержимым
- •Сервер доставляет данные, а не содержимое
- •Реальное кодирование требует порядка
- •Применение богатых клиентов Ajax
- •Системы, созданные с использованием Ajax
- •Google Maps
- •Альтернативные технологии
- •Macromedia Flash
- •Java Web Start
- •Резюме
- •Ресурсы
- •Основные элементы Ajax
- •JavaScript изучался не зря
- •Определение внешнего вида с помощью CSS
- •Селекторы CSS
- •Свойства стилей
- •Простой пример использования CSS
- •Обработка DOM с помощью JavaScript
- •Поиск узла DOM
- •Создание узла DOM
- •Добавление стилей к документу
- •Свойство innerHTML
- •Асинхронная загрузка с использованием XML
- •Элементы IFrame
- •Объекты XmlDocument и XMLHttpRequest
- •Использование фуниции обратного вызова для контроля запроса
- •Жизненный цикл процедуры поддержки запроса
- •Отличия Ajax от классических технологий
- •Резюме
- •Ресурсы
- •Порядок из хаоса
- •Образы разработки
- •Реструктуризация и Ajax
- •Во всем надо знать меру
- •Реструктуризация в действии
- •Варианты применения реструктуризации
- •Несоответствие браузеров: образы разработки Fagade и Adapter
- •Управление обработчиками событий: образ разработки Observer
- •Повторное использование обработчиков событий: образ разработки Command
- •Обеспечение единственной ссылки на ресурс: образ разработки Singleton
- •"Модель-представление-контроллер "
- •Серверная программа Ajax, созданная без применения образов разработки
- •Реструктуризация модели
- •Разделение содержимого и представления
- •Библиотеки независимых производителей
- •Библиотеки, обеспечивающие работу с различными браузерами
- •Компоненты и наборы компонентов
- •Элементы, располагаемые на стороне сервера
- •Резюме
- •Ресурсы
- •Применение архитектуры MVC к программам различных уровней
- •Применение архитектуры MVC к объектам, присутствующим в среде браузера
- •Представление в составе Ajax-приложения
- •Отделение логики от представления
- •Отделение представления от логики
- •Контроллер в составе Ajax-приложения
- •Классические JavaScript-обработчики
- •Модель обработки событий W3C
- •Реализация гибкой модели событий в JavaScript
- •Модель в составе Ajax-приложения
- •Использование JavaScript для моделирования предметной области
- •Взаимодействие с сервером
- •Генерация представления на основе модели
- •Отражение объектов JavaScript
- •Обработка массивов и объектов
- •Включение контроллера
- •Резюме
- •Ресурсы
- •Программы, выполняемые на сервере
- •Создание программ на стороне сервера
- •N-уровневые архитектуры
- •Управление моделью предметной области на стороне клиента и на стороне сервера
- •Принципы создания программ на сервере
- •Серверные программы, не соответствующие основным принципам разработки
- •Использование архитектуры Model!
- •Использование архитектуры на базе компонентов
- •Архитектуры, ориентированные на использование Web-служб
- •Частные решения: обмен данными
- •Взаимодействие, затрагивающее только клиентскую программу
- •Пример отображения информации о планетах
- •Взаимодействие, ориентированное на содержимое
- •Взаимодействие, ориентированное на сценарий
- •Передача данных серверу
- •Использование HTML-форм
- •Использование объекта XMLHttpRequest
- •Управление обновлением модели
- •Резюме
- •Ресурсы
- •Создание качественного приложения
- •Отклик программы
- •Надежность
- •Согласованность
- •Простота
- •Как получить результат
- •Предоставление сведений пользователю
- •Поддержка ответов на собственные запросы
- •Обработка обновлений, выполненных другими пользователями
- •Создание системы оповещения
- •Основные принципы оповещения
- •Реализация базовых средств оповещения
- •Отображение пиктограмм в строке состояния
- •Отображение подробных сообщений
- •Формирование готовой системы
- •Предоставление информации в запросах
- •Информация о новизне данных
- •Простой способ выделения данных
- •Выделение данных с использованием библиотеки Scriptaculous
- •Резюме
- •Ресурсы
- •JavaScript и защита браузера
- •Политика "сервера-источника"
- •Особенности выполнения сценариев в Ajax-приложении
- •Проблемы с поддоменами
- •Взаимодействие с удаленным сервером
- •Взаимодействие с Web-службами
- •Защита конфиденциальной информации
- •Вмешательство в процесс передачи данных
- •Организация защищенного НТТР-взаимодействия
- •Передача шифрованных данных в ходе обычного HTTP-взаимодействия
- •Управление доступом к потокам данных Ajax
- •Создание защищенных программ на уровне сервера
- •Ограничение доступа к данным из Web
- •Резюме
- •Ресурсы
- •Что такое производительность
- •Скорость выполнения JavaScript-программ
- •Определение времени выполнения приложения
- •Использование профилировщика Venkman
- •Оптимизация скорости выполнения Ajax-приложения
- •Использование памяти JavaScript-кодом
- •Борьба с утечкой памяти
- •Особенности управления памятью в приложениях Ajax
- •Разработка с учетом производительности
- •Простой пример управления памятью
- •Как уменьшить объем используемой памяти в 150 раз
- •Резюме
- •Ресурсы
- •Сценарий двойной комбинации
- •Недостатки клиентского решения
- •Недостатки клиентского решения
- •Архитектура клиента
- •Разработка взаимодействия клиент/сервер
- •Реализация сервера: VB.NET
- •Написание кода сервера
- •Представление результатов
- •Применение каскадных таблиц стилей
- •Дополнительные вопросы
- •Запросы при выборе нескольких элементов
- •Переход от двойного связного выбора к тройному
- •Реструктуризация
- •Новый и улучшенный объект netContentLoader
- •Создание компонента двойного списка
- •Резюме
- •Глава 10. Опережающий ввод
- •Изучаем опережающий ввод
- •Типичные элементы приложений опережающего ввода
- •Google Suggest
- •Ajax как средство опережающего ввода
- •Структура серверной части сценария: С#
- •Сервер и база данных
- •Тестирование серверного кода
- •Структура клиентской части сценария
- •HTML
- •JavaScript
- •Обращение к серверу
- •Дополнительные возможности
- •Реструктуризация
- •День 1: план разработки компонента TextSuggest
- •День 3: включаем Ajax
- •День 4: обработка событий
- •День 5: пользовательский интерфейс всплывающего окна с предлагаемыми вариантами
- •Итоги
- •Резюме
- •Эволюционирующий портал
- •Классический портал
- •Портал с богатым пользовательским интерфейсом
- •Создание портала с использованием Java
- •Таблица пользователя
- •Серверная часть кода регистрации: Java
- •Структура регистрации (клиентская часть)
- •Реализация окон DHTML
- •База данных окон портала
- •Серверный код окна портала
- •Добавление внешней библиотеки JavaScript
- •Возможность автоматического сохранения
- •Адаптация библиотеки
- •Автоматическая запись информации в базе данных
- •Реструктуризация
- •Определение конструктора
- •Адаптация библиотеки AjaxWindows.js
- •Задание команд портала
- •Выводы
- •Резюме
- •Понимание технологий поиска
- •Классический поиск
- •"Живой" поиск с использованием Ajax и XSLT
- •Возврат результатов клиенту
- •Код клиентской части сценария
- •Настройка клиента
- •Инициализация процесса
- •Код серверной части приложения: РНР
- •Создание XML-документа
- •Создание документа XSLT
- •Объединение документов XSL и XML
- •Совместимость с браузером Microsoft Internet Explorer
- •Совместимость с браузерами Mozilla
- •Последние штрихи
- •Применение каскадных таблиц стилей
- •Улучшение поиска
- •Поддержка браузерами Opera и Safari
- •Использовать ли XSLT
- •Решение проблемы закладок
- •Реструктуризация
- •Объект XSLTHelper
- •Компонент "живого" поиска
- •Выводы
- •Резюме
- •Считывание информации из внешнего мира
- •Поиск XML-лент
- •Изучение структуры RSS
- •Богатый пользовательский интерфейс
- •Чтение лент
- •HTML-структура без таблиц
- •Гибкое CSS-форматироеание
- •Глобальный уровень
- •Предварительная загрузка средствами Ajax
- •Богатый эффект перехода
- •Правила прозрачности, учитывающие индивидуальность браузеров
- •Реализация затухающего перехода
- •Интеграция таймеров JavaScript
- •Дополнительные возможности
- •Введение дополнительных лент
- •Интеграция функций пропуска и паузы
- •Как избежать ограничений проекта
- •Обход системы безопасности браузеров Mozilla
- •Изменение масштаба приложения
- •Реструктуризация
- •Модель приложения
- •Представление приложения
- •Контроллер приложения
- •Выводы
- •Резюме
- •Отладчики
- •Для чего нужен отладчик
- •Средство Safari DOM Inspector для Mac OS X
- •Ресурсы
- •JavaScript — это не Java
- •Формирование объектов
Глава 10. Опережающий ввод АЛЛ
Мы можем предложить более продуманное решение этой проблемы, введя в специальный объект дополнительный параметр и отправив его на сервер. Есть и другая возможность — работать с тем, что мы имеем, и внести в код минимальные изменения. В таком случае простое решение включает изменение одной строки кода и добавление оператора if в код серверной части сценария.
Итак, нам требуется каким-то образом научиться различать элементы на сервере, определяя, какой элемент потребовал дообработки. Сообщить о различии проще всего с помощью имени, содержащегося в элементе. В данном случае мы ссылаемся на имя текстового окна. Для внедрения описанной возможности мы изменили строку параметров так, как показано в листинге 10.20.
Листинг 10.20. Измененная функция TypeAhead() function TypeAhead(xStrText){
|
var strParams = "q=" + xStrText + "&where=" + |
|
|
theTextBox.obj.matchAnywhere + "&name=" + theTextBox.name; |
|
|
var loaderl = new net.ContentLoader(theTextBox.obj.serverCode, |
|
_} |
BuildChoices,null,"POST",strParams); |
|
m |
||
|
|
|
Немного изменив переменную strParams в функции TypeAhead(), в параметрах формы, отправляемых на сервер, мы теперь передаем имя текстового окна. Это означает, что мы можем обращаться к этому значению на сервере и использовать оператор if-else либо case для запуска другого запроса. В таком случае нам не требуется реализовывать несколько страниц, соответствующих различным элементам.
10.5. Реструктуризация
Разработав достаточно сильный набор функций, обеспечивающих возможности опережающего ввода, мы можем подумать, как реструктуризировать все эти возможности в более удобном для использования виде. То, что мы создали на текущий момент, обеспечивает функциональные возможности, необходимые для предоставления на выбор ряда вариантов. Однако данная структура имеет свои недостатки с точки зрения работы, требуемой от разработчика при внедрении ее на Web-страницу (или на 20-30 Web-страниц).
Давайте на минуту представим, что перед нами, как перед главным архитектором использующей Ajax Web-структуры, поставлена задача написать компонент опережающего ввода, который будет использовать вся компания. После завершения вводного собрания мы получаем краткий перечень функциональных требований. Не совсем еще понимая суть дела, мы просматриваем этот документ (табл. 10.2).
По мере изучения списка нам в голову начинают приходить различные гысли. Прежде всего, руководство, похоже, не понимает концепцию приоритета. Но поскольку этого стоило ожидать, давайте рассмотрим суть — требо-
412 |
Часть IV. Ajax в примерах |
|
Таблица 10.2. Наши функциональные требования |
|
|
Номер Описание требования |
Приоритет |
|
1 |
Компонент должен работать с существующей разметкой HTML, не |
1 |
|
требуя никакого ее изменения. Допускается лишь простая модификация |
|
|
заголовка с целью внедрения линии поведения компонента |
|
2 |
Компонент должен без дополнительных усилий поддерживать |
1 |
|
многократное использование на одной странице |
|
3Должна существовать возможность индивидуальной настройки каждого 1 экземпляра компонента Под этим имеются в виду как аспекты поведения (например, учет регистра, поиск с любого места), так и стилевое оформление CSS
4 |
Компонент не должен вводить глобальные переменные. Компания |
1 |
|
пользуется сторонними библиотеками JavaScript, и глобальное |
|
|
пространство имен уже достаточно засорено. Использование любых |
|
|
глобальных имен (кроме названия самого компонента) строго |
|
|
запрещено |
|
5 |
Компонент должен предоставлять разумные значения по умолчанию |
1 |
|
для всех конфигурационных опций |
|
6 |
Компонент должен работать в Internet Explorer и Firefox |
1 |
7 |
Для уменьшения работ по кодированию, требуемых для улучшения |
1 |
|
качества и надежности решения, компонент должен быть создан на |
|
|
основе структуры с открытым исходным кодом |
|
8 |
Кстати, если получится, сделайте это до конца недели |
1 |
вания. Несмотря на то что мы проделали немалую работу, имеющийся сценарий не удовлетворяет даже половине из них. Сценарий уже готов, поэтому о требовании 7 можно забыть: нам не нужно уменьшать объем работ. Очевидно, что требованию 8 сценарий также удовлетворяет (по той же причине). Он поддерживает различные браузеры, поэтому снимаем и требование 6. А вот что касается остального, то определенную работу проделать все же придется. У нас есть всего неделя, поэтому начнем.
10.5.1. День 1: план разработки компонента TextSuggest
Прежде всего нам нужно определиться с тем, как поднять производительность и уложиться в отведенное время. Один из лучших способов — переложить работу на другихЕсли кто-то может сделать часть работы, пусть он ее для нас сделает. В данном случае мы собираемся воспользоваться библиотекой с открытым исходным кодом Rico (http: //openrico. org) и расширением Prototype.js (http://prototype.conio.net/). Библиотека Rico предлагает некоторую инфраструктуру Ajax, эффекты и вспомогательные методы, которые повысят скорость нашей разработки. Prototype предлагает инфраструктуру Для прекрасных синтаксических идиом, благодаря которым наш код будет выглядеть понятнее и потребует меньше времени на разработку. Поэтому давайте внимательно изучим последствия использования Prototype и Rico.
Глава 10 Опережающий ввод 413
prototype
prototype предлагает разработчикам несколько расширений основного объекта JavaScript, а также несколько функций, способствующих поддержанию хорошего стиля кодирования. Ряд из них мы используем в нашем примере.
Объект Class
Объект Class, представленный в библиотеке Prototype, имеет единственный метод create (), отвечающий за создание экземпляров, которые могут иметь любое число методов. Метод create {) возвращает функцию, вызывающую другой метод того же объекта — i n i t i a l i z e (). Звучит немного сложно, но на практике все просто По сути, таким образом формируется синтаксическая основа для задания типов в JavaScript. Идиома выглядит следующим образом:
var TextSuggest = Class.create(); TextSuggest.prototype = {
// Вызывается в процессе создания
initialize: function( pi, p2, p3 ) {
h
};
В данном фрагменте кода создается то, что можно считать "классом" (хотя сам язык не поддерживает такой концепции), и определяется функцияконструктор i n i t i a l i z e (). Клиент компонента может создавать экземпляры класса с помощью приведенной ниже строки кода.
var textSuggest = new TextSuggest(pi, p2, p3);
Метод extend О
Библиотека Prototype расширяет базовый объект JavaScript и добавляет метод, именуемый extend(), открывая этот метод для всех объектов. Метод extend () принимает в качестве параметров два объекта: базовый объект и объект, который будет его расширять. Свойства расширяющего объекта переносятся на базовый объект. Это позволяет использовать механизм расширения объектов на уровне экземпляров. Этой возможностью мы воспользуемся позже, когда будем реализовывать для настраиваемых параметров компонента TextSuggest значения по умолчанию.
Метод bind/bindAsEventListener()
Библиотека Prototype также добавляет два метода к объекту Function: bind() и bindAsEventListener(). Эти методы предлагают синтаксически элегантный способ создания замыкания функций. Напомним, как мы создавали замыкания в других примерах:
oThis • this;
this.onclick = function() { oThis.callSomeMethod() };
С помощью метода bind() библиотеки Prototype того же результата можно добиться гораздо проще.
this.onclick = this . callSomeMethod.binci( this);
API bindAsEventHandler() передает методу объект Event и сглаживает различия между Internet Explorer и стандартизованной W3C моделью событий!
414 Часть IV. Ajax в примерах
Метод $ — синтаксическая "конфетка"
В JavaScript в названиях методов можно использовать определенные специальные символы, например знак доллара ($). В библиотеке Prototype этот малоизвестный факт используется для инкапсуляции в метод одной из наиболее распространенных задач в DHTML-программировании: извлечения элемента из документа на основе его идентификатора. Таким образом, в нашем коде мы сможем писать конструкции следующего типа:
$('textField').value = aNewValue;
При этом мы обходимся без указанных ниже громоздких структур.
var textField = document.getElementByldf'textField1 ) textField.value = aNewValue;
Rico
Используя Rico, мы получаем Prototype бесплатно. Посмотрим, что нам требуется от Rico. Rico предлагает богатый набор линий поведения, возможностей перетаскивания и кинематических эффектов, но поскольку мы пишем компонент, использующий единственное текстовое поле, то большинство из доступных возможностей нам не понадобится. Однако еще есть прекрасный обработчик Ajax и некоторые вспомогательные методы, предлагаемые Rico. Вспомогательные методы Rico мы рассмотрим по ходу разбора примера, а сейчас остановимся на предлагаемой Rico инфраструктуре Ajax. Возможности Ajax Rico публикуются посредством единственного объекта, доступного для документа ajaxEngine. API ajaxEngine предоставляет поддержку для регистрации логических имен для запросов и регистрации объектов, знающих, как обрабатывать ответы Ajax. Рассмотрим, например, следующий код:
ajaxEngine.registerRequest( 'getlnvoiceData', 'someLongGnarlyUrl.do' ) ;
ajaxEngine.registerAjaxObject( 'xyz', someObject );
В первой строке кода регистрируется логическое имя потенциально громоздкого URL Ajax. Далее при отправке запросов можно использовать это логическое имя, не отслеживая упомянутый громоздкий URL. Пример такого использования приведен ниже.
ajaxEngine.sendRequest('getlnvoiceData', request parameters . . . );
Метод registerRequest () локализует использование указателей URL — теперь они встречаются только в одном месте, обычно это обработчик событий onload в разделе тела. Если URL требуется изменить, это можно сделать в месте регистрации, не затрагивая остальную часть кода-
Метод registerAjaxObject() иллюстрирует регистрацию объекта обработки Ajax. В предыдущем примере подразумевалось, что в ответах необходимо обращаться к объектной ссылке someObject с помощью логического имени xyz, причем эта ссылка необходима для обработки ответов Ajax посредством метода ajaxUpdate ().
Исходя из того, что мы используем описанные функциональные возможности объекта ajaxEngine, нам осталось только рассмотреть ответный XML-
Глава 10 Опережающий ввод 415
документ, ожидаемый процессором Ajax. Этот документ немного отличается от динамически генерируемого сценария JavaScript, который возвращался в предыдущей версии данного примера, но Rico ожидает получить XML. Все элементы <response> документа должны находиться внутри элемента верхнего уровня <ajax-response>. Внутри указанного элемента сервер может возвращать столько элементов <response>, сколько требует приложение. Такая возможность очень удобна, поскольку позволяет серверу возвращать ответы, обрабатываемые различными объектами, обновляющими потенциально несвязанные области Web-страницы, — например, для обновления области состояния, области данных и конечной области вывода. XML-документ для предыдущего примера приведен ниже.
<аj ax-response>
<response type="object" id="xyz">
. . . the r e s t of the XML response as normal . . .
</response> <response ... >
more response elements if needed.. </response>
</ajax-response>
Данный XML-документ указывает ajaxEngine, что данный запрос должен обработать объект, зарегистрированный с идентификатором xyz. Процессор Ajax находит объект, зарегистрированный с именем xyz, и передает содержимое соответствующего элемента <response> методу ajaxUpdate().
Вот и все. День получился довольно коротким. Некоторое время мы потратили на изучение структур с открытым исходным кодом, на которые мы можем опираться, и разработали план внедрения их в требуемый компонент. Мы еще не написали ни строчки кода, но решили, как ускорить дальнейшую работу над проектом. Кроме того, мы подобрали платформу, которая поможет повысить производительность работы (удовлетворив при этом требованию 7 технического задания). Кодирование начнется завтра.
10.5.2.День 2: создание TextSuggest — понятного
инастраиваемого компонента
Теперь, когда у нас есть хорошая технологическая платформа, мы можем создавать на ней свой компонент. При работе над проектами часто удобно идти от желаемого результата, заранее думая о контракте нашего компонента. Напомним наше первое требование.
Требование 1. Компонент должен работать с существующей разметкой HTML, не требуя никакого ее изменения. Допускается лишь простая модификация заголовка для внедрения линии поведения компонента.
Из-за этого требования мы оставляем нетронутым практически все, что находится внутри элемента <body>. Поэтому предположим, что нам требуется ввести сценарий в HTML посредством HTML-кода, подобного приведенному в листинге 10.21.
416 Часть IV. Ajax в примерах
Листинг 10.21. HTML-разметка компонента TextSuggest
<html> |
|
|
|
<head> |
|
|
|
<script> |
|
|
|
v a r s u g g e s t O p t i o n s = { / * d e t a i l s |
to |
come*/ }; |
|
f u n c t i o n |
i n j e c t S u g g e s t B e h a v i o r ( ) { |
// |
Создать компонент в <head> |
sugges t |
= new TextSuggest( |
|
|
1 f i e l d l ' , ' t y p e A h e a d D a t a . a s p x ' , s u g g e s t O p t i o n s ) ;
}>;
</ s c r i p t > </head>
<body o n l o a d = " i n j e c t S u g g e s t B e h a v i o r ( ) " > <form name="Forml">
AutoComplete Text Box:
< i n p u t t y p e = " t e x t " id—"fieldl" n a m e = " t x t U s e r I n p u t " > _ - </form>
</body>
</html>
Смысл приведенного HTML-кода заключается в том, что нам требуется создать объект с идентификатором текстового поля, к которому мы будем привязаны, указателем URL источника данных Ajax и набором конфигурационных объектов, которые еще будут заданы. (Чтобы это сработало, текстовое поле должно иметь идентификатор.) Все, что находится внутри элемента <body>, остается без изменений. Разобравшись с этим, займемся конструктором. Имя создаваемого компонента TextSuggest помещается в глобальное пространство имен с помощью функции-конструктора, которая (как вы помните) генерируется методом Clas s. create {) библиотеки Prototype, как показано в листинге 10.22.
Листинг 10.22. Конструктор TextSuggest
TextSuggest = Class.create(); TextSuggest.prototype = { initialize:
function{anld, url,
options) {//О Ссылка на входной элемент this.id = anld;
this.textlnput = $(this.id);
var browser = navigator.userAgent.toLowerCase();
//© Детектировать тип браузера this.isIE =
browser.indexOff"msie") != -1; this-isOpera =
browser.indexOf{"opera")!= -1; // © Установить значения по умолчанию
this.suggestions = []; this.setOptions(options); this.initAjax(url);
Ьthis.inj ectSuggestBehavior();
}±11 |
• |
|
|
|
|
Глава 10. Опережающий ввод 417
Разберем этот конструктор. Как упоминалось ранее, конструктору передается идентификатор текстового ввода, с которым нужно связать предложение вариантов. Для поля ввода хранится ссылка как на идентификатор, так л на элемент DOM О. Далее определяется браузер пользователя и записывается состояние, которое понадобится компоненту позже, когда потребуется информация о среде времени выполнения этого браузера ©. В данном случае специальный код требуется только для Internet Explorer и Opera, поэтому проверяется использование только этих браузеров.
Настройка Ajax и введение в код нужной линии поведения будет рассмотрен позже ©. Пока же (до конца дня) сосредоточимся на возможности настройки компонентов. Как вы помните, ранее была создана функция Setproperties (), содержащая все настраиваемые аспекты нашего сценария.
function SetProperties
(xElem, xHidden, xserverCode, xignoreCase, xmatchAnywhere, xmatchTextBoxWidth, xshowNoMatchMessage, xnoMatchingDataMessage, xuseTimeout, xtheVisibleTime){
}
Написанный код удовлетворяет требованию, которое касается возможности настройки, но не обеспечивает удобный API или подходящие значения по умолчанию. Для решения этих проблем вводится объект опций, который передается конструктору. Объект опций содержит свойство для каждого конфигурационного параметра компонента опережающего ввода. Теперь нужно заполнить опции конфигурационными параметрами.
var suggestOptiona - { matchAnywhere : true, ignoreCase : true }; function injectSuggestBehavior() {
suggest = new TextSuggest('fieldl', ' typeAheadXML.aspx', suggestOptions ); } ) ;
Данная простая идиома предлагается следующие дополнительные преимущества.
•Благодаря ей сигнатура конструктора выглядит понятнее. Сигнатура клиентских страниц, на которых используется наш компонент, может создаваться всего с тремя параметрами.
•Можно вводить дополнительные конфигурационные параметры, не меняя контракт конструктора.
•Можно написать изящную функцию setoptions(), предоставляющую значения по умолчанию для всех незаданных свойств, и позволить пользователю задавать только те свойства, которые он желает изменить.
Впоследнем пункте описано именно то, что делает метод setOptions (), включенный в конструктор ранее ©. Разберем его.
setOptions: function(options) {
t h i s , o p t i o n s • { suggestDivClassName: ' s u g g e s t D i v ' ,
