Проект Порталус


 

CompDocs on-line

Инвестиции WebMoney

 
CompDocs
Вебмастеру
Программисту
Пользователю
Геймеру
Мабила
Новости
Отдохни
Беседка
Обои
Docs.com.ru

Web-мастеру:

PHP
ASP .NET
Perl
JavaScript
CSS
HTML
Раскрутка
Сервисы

Программисту:

DirectX
OpenGL
Pascal
Алгоритмы

Пользователю:

Windows
Linux
BIOS
Обои

Посетителю:

Форум
Юмор
Рассылки
Объявления
ФизМат
Тесты
Работа


Книги с доставкой

Общие вопросы, справочная литература (97)

Для начинающих (214)

Аппаратное обеспечение: компьютеры, периферия, оргтехника (54)

Базы данных. СУБД (65)

Интернет (85)

Компьютерная безопасность. Хакинг, крэкинг, фрикинг (29)

Компьютерные сети и протоколы (45)

Операционные системы (143)

Программное обеспечение (447)

Языки и среды программирования, технологии и т.п. (323)

Прочие издания (46)


 

Автор: Александр Рябов

Кто был ничем, тот станет всем. Кратко об объектах в JS

"Перемен!" - требуют наши сердца.
"Перемен!" - требуют наши глаза.
В нашем смехе и в наших слезах, и в пульсации вен!
Перемен! Мы ждем перемен...

В. Цой

О том, о сем...
Объект - он и в Африке объект. И JS не отличается особой оригинальностью на этот счет: объект - это конструкция, в которой мирно уживаются свойства (обычные переменные либо другие объекты) и методы (функции). Договоримся называть свойства и методы объекта, вместе взятые, его составляющими.

Доступ к свойствам объекта осуществляется с помощью "точечной" нотации:
   object.property
либо с помощью "массивной" ;) нотации:
   object["property"].

Вторая нотация удобна, когда имя свойства, с которым работаем, заранее не известно (и поэтому не указано в коде скрипта), а находится в переменной. К примеру, пусть переменная prop="counter" - задает имя некоторого свойства объекта obj. Тогда "точечная" нотация для обращения к этому свойству выглядит так:
   eval("obj."+prop) - на чтение (и запись для свойств-объектов), и
   eval("obj."+prop+"="+value) - на запись (для свойств-необъектов).
А "массивная":
   obj[prop] - на чтение и запись.
Преимущества второй нотации очевидны.

Примечание – А.Р.
Раздвоение ситуации с eval связано с тем, что eval возвращает ссылку только для объектов. Для всех других типов данных – возвращается значение.

«Массивная» нотация позволяет рассматривать объекты как ассоциативные массивы (т.к. индексами в таком массиве являются строки).

Все, что сказано о доступе к свойствам объекта, верно и для методов, вот только после обеих нотаций нужно использовать скобки с параметрами вызова или без таковых, т.к. без скобок нотация для метода дает доступ к исходному тексту метода. Этот доступ – как на чтение, так и на запись. Но запомните, что присвоение этому свойству нового исходного текста преобразовывает метод в свойство типа string (это легко проверить с помощью typeof()).

Примеры обращения к методам.
obj.f() <=> obj["f"]()
obj.count(1,2) <=> obj["count"](1,2)

Пример ошибки.
obj.f (или obj["f"]) = "function anonymous() { return 1; }" – в результате метод obj.f становится строкой.

Утверждения для манипулирования объектами.
Итератор составляющих объекта:
   for (name in obj)

В этом цикле переменная name пробегает множество значений имен составляющих объекта obj (не обязательно в лексикографическом порядке. Совсем не обязательно ;))

Пример.
/* Вывод всех пар составляющая-значение для объекта window: */
for ( var i in window)
 document.write(i + " = " + window[i] + "<br>");

Утверждение with («группировщик»):
   with (obj) {
    …
   }

Устанавливает для набора утверждений в фигурных скобках объект по умолчанию. Если какое-либо имя, использованное в этих утверждениях не найдено среди локальных и глобальных имен, тогда поиск выполняется по составляющим объекта. Если таковое найдено, оно применяется.

Пример.
/* считаем, что переменных x и y в охватывающей программе НЕТ */
with (obj) {
 x = 1;
 y = 2;
}

то же, что и
obj.x = 1; obj.y = 2;

Создание новых объектов.
Кроме определенных по умолчанию (Array, Math и др.), JS допускает создание новых типов объектов.
Для создания нового типа объекта вначале необходимо описать его конструктор, который представляется собой обычную функцию, а потом использовать оператор new. Например:

function obj() {

}
– становится конструктором при вызове: A = new obj().

В указанном примере объект A не имеет ни свойств, ни методов. Для определения свойств в конструкторах используется ключевое слово this. Например:

function obj( x0) {
 this.x = x0;
}
– при вызове A = new obj(5) создается объект со значением свойства x = 5.

Похожим образом определяются методы объектов: this.f = fname, где fname – имя существующей функции (без кавычек). Внутри методов ключевое слово this применяется для доступа к контексту содержащего этот метод объекта. Пример:

function sum() {
 return this.x+this.y;
}
function sumator( x0, y0) {
 this.x = x0;
 this.y = y0;
 this.f = sum;
}
A = new sumator(3,8);

A.f() возвращает 11.

При таком способе определения, как видим, методы находятся в глобальном пространстве имен. Однака, можно полностью скрыть код метода в объекте. Для этого нужно использовать объект Function. Вот пример того, как это делается:

function sumator( x0, y0) {
 this.x = x0;
 this.y = y0;
 this.f = new Function("return this.x+this.y;");
}
A = new sumator(3,8);

A.f() возвращает 11.

Общий формат вызова конструктора объекта Function таков:
   new Function("arg1","arg2",…,"argN","code"),

т.е. вначале перечисляются параметры функции, а потом записывается тело функции.
В качестве примера метода с параметрами приведем следующий код (считаем, что этот код записан внутри конструктора sumator):
this.scalar = new Function("xp","yp","return xp*this.x+yp*this.y;");
Тогда A.scalar(-2,1) вернет 2.

Тело функции, разумеется, может состоять не только из одного предложения языка. Если предложений несколько – их можно записать в одну строку либо в несколько строк, пользуясь символом продолжения строки - "\". Пример:

this.x_sqrt = new Function("if (this.x>0) return Math.sqrt(this.x); return 0;");

или, что то же самое:

this.x_sqrt = new Function("\
 if (this.x>0)\
  return Math.sqrt(this.x);\
 return 0;\
");

Второй способ записи, разумеется, удобнее.

Прототипы.
JS – объектно-ориентированный язык, основанный на прототипах (C++, Java – основаны на классах). Каковы основные отличия между прототипными и "классовыми" языками? Приведем их в виде таблицы на примере Java и JS.

JavaJS
Класс и экземпляр нетождественны.Все объекты являются экземплярами.
Класс как таковой объявляется отдельно, экземпляры – порождаются вызовами конструкторов.Объявление и создание объектов – все это выполняет конструктор.
Построение иерархии объектов производится в объявлениях классов.Построение иерархии объектов выполняется установкой одного объекта прототипом другого.
Свойства наследуются согласно цепочке классов.Свойства наследуются согласно цепочке прототипов.
Объявление класса определяет все составляющие всех экземпляров класса. Динамически добавлять новые составляющие нельзя.Конструктор или прототип определяют начальное множество составляющих. Можно добавлять и удалять новые составляющие в отдельных экземплярах или во всех экземплярах данного типа объектов динамически.

Итак, разберем некоторые особенности JS, как прототипного языка.

К любому созданному экземпляру объекта в любое время можно добавить новые составляющие. Делается это с помощью простого присваивания.

Пример.
function obj( x0) {
 this.x = x0;
}
A = new obj(1);
A.y = 5;
B = new obj(2);

Объект A имеет два свойства: x и y. Но объект B имеет только свойство x, т.к присваивание A.y=5 создает новое свойство только у объекта A, а не у всех объектов типа obj.

Удаление составляющих производится с помощью оператора delete: delete A.y; - и A состоит только из свойства x.

Чтобы добавлять/удалять составляющие из всех экземпляров данного типа объектов необходимо обратиться к прототипу – свойству prototype.

Пример.
function obj( x0) {
 this.x = x0;
}
A = new obj(1);
obj.protopype.y = 5;
B = new obj(2);

Объекты A и B имеют два свойства: x и y. И у обоих значение свойства y равно 5.

С помощью свойства prototype (и никак иначе) строится иерархия объектов. Это свойство является простым значением, т.к. в JS допустимо только простое наследование, т.е. у всякого объекта может быть не больше одного непосредственного предка.

Пример наследования.
function trig() {
 this.sin = Math.sin;
 this.cos = Math.cos;
}

function trig_hypo() {
 this.sh = new Function("x","return (Math.exp(x)-Math.exp(-x))/2");
 this.ch = new Function("x","return (Math.exp(x)+Math.exp(-x))/2");
}
trig_hypo.prototype = new trig;

Теперь объект trig_hypo содержит четыре метода, два из которых пронаследованы от trig.

Ну что же, общий принцип создания иерархии объектов, думаю, понятен. Однако, не все так просто, как может показаться на первый взгляд. В Core JavaScript Guide 1.5 описаны некоторые «подводные камни», которые подстерегают разработчика иерархии объектов в самом безобидном коде. Настоятельно рекомендую ознакомиться с разделом Details of the Object Model из указанной документации перед тем, как серьезно заниматься объектно-ориентированным программированием на JS.

Что почитать?
Документация по JS от NetScape на http://developer.netscape.com/docs/manuals/javascript.html

Благодарю всех за внимание!

Александр Рябов. Август 2004, Украина.
ryabov@ua.fm

Ссылки по теме:

  • Учебник JavaScript
  • *.JS, когда грузиться думаешь?
  • JavaScript спешит на помощь - 1
  • JavaScript спешит на помощь - 2
  • JavaScript спешит на помощь - 3
  • JavaScript скрипты
  • Комментарии к статье
    Ваше имя:

    Комментарий:

    Copyright © 2003-2004 Путяк Владислав.
    Использование материалов журнала разрешается только с указанием ссылки на первоисточники и сайт журнала - http://docs.com.ru



    @ portalus.ru