Функции в javascript. Урок 3. Конструкторы

Оглавление цикла уроков по функциям в javascript.

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

Как известно, javascript является объектно-ориентированным языком, однако, в отличие от многих других языков, в нем нет никаких классов вообще. Как же создать объект? Первый способ — задать объект с помощью литерала. Причем, мы можем задавать имена полей с помощью любых символов:

Функции-конструкторы

Еще один способ создания объектов в javascript, приближающий его к языкам «с классами» — с помощью функций-конструкторов и оператора new:

Оператор new в языке javascript — это особый способ вызвать функцию. Любую функцию. При этом первым делом создается пустой объект (на самом деле, не совсем пустой, об этом ниже и в следующем уроке), и далее происходит применение функции-конструктора к этому созданному объекту (о применении функций можно прочитать в предыдущем уроке), то есть внутри конструктора переменная this будет ссылаться на этот объект. И в конце неявно происходит возврат этого объекта, то есть, по сути, автоматически выполняется инструкция return this.

У этого объекта также будет определено поле constructor, которое является ссылкой на функцию-конструктор, породившую его. Так можно, например, узнать имя этой функции:

Другой способ проверить, создан ли объект данным конструктором (то есть как бы принадлежит данному «классу» или «типу»), — использовать оператор instanceof:

Кстати, так же можно определять принадлежность переменных и ко встроенным типам, таким как Array, Function, Date и т.д.

При желании из конструктора можно явно вернуть любой другой объект (именно объект, возврат примитивных типов игнорируется), изначальный объект при этом исчезает:

Универсальная функция-конструктор

Функция-конструктор — это просто функция, ее можно вызвать и обычным способом без new, так же как и любую функцию можно вызвать с помощью оператора new. Другой вопрос, что может получиться полная чушь и в том, и в другом случае. Мы можем написать конструктор таким образом, чтобы он мог вызываться без new, оставаясь при этом полноценным конструктором. Для этого нужно сначала проверить, является ли this объектом, созданным нашим конструктором, если нет — вызвать себя же через new и вернуть получившийся объект:

«Пространства имен»

А что, если конструктор является при этом методом какого-то объекта и вызывается через new, но именно как метод этого объекта? На что тогда ссылается this внутри конструктора? Тут не надо излишне усложнять — this при вызове через new всегда ссылается на вновь созданный объект, и неважно, где у нас находится функция-конструктор. Это довольно распространенная практика — размещать конструкторы в полях объектов, эмулируя тем самым пространства имен, которых нет в javascript, это помогает не захламлять глобальный контекст кучей конструкторов. Вот пример:

Публичные и защищенные поля и методы

В javascript нет такого понятия, как защищенные поля и методы, все они являются публичными, доступными извне объекта. Но все же есть способ сделать защищенные переменные и функции, доступные только методам самого объекта: на помощь приходит замыкание, созданное внутри конструктора, но при этом методы объекта, которые хотят получить доступ к этим защищенным сущностям, должны быть заданы также внутри конструктора. Рассмотрим сначала случай защищенных переменных:

Присвоение содержимого аргумента text локальной переменной protectedText, по сути, лишнее действие, поскольку text сама является локальной переменной и доступна в созданном замыкании.

В случае защищенных методов есть одна небольшая тонкость. На самом деле это не методы, а просто локальные функции, определенные в контексте конструктора и сохраненные в замыкании. Публичные методы, которые хотят иметь доступ к защищенным, опять же, должны быть заданы в конструкторе. Но проблема возникает, когда публичный метод вызовет защищенную функцию, просто как функцию, а ей будет необходимо получить доступ к полям или методам нашего объекта. Загвоздка в том, что если вызвать функцию в лоб, то this внутри нее будет ссылаться на глобальный объект, а не на текущий. Вот немного надуманный пример:

В этом примере мы получим совсем не то: внутри вызова protectedGetText() переменная this указывает на window. Одно из решений проблемы — вызвать функцию через call() или apply(), перепишем определение метода getText():

Либо можно в контексте конструктора создать новую переменную, например, self, которая будет хранить ссылку на текущий объект и которая будет использоваться в защищенных функциях вместо this:

Кстати, такая практика с использованием псевдонима для this довольно распространена при работе с событиями и ajax-запросами:

Если мы в callback-функции напишем this вместо self, то ссылаться она будет на глобальный объект window, поскольку ajax-механизмом эта функция вызовется «по-простому», без привязки к какому-либо объекту (функция ajaxGet в данном случае — это некая абстрактная реализация технологии ajax).

В следующем уроке мы продолжим знакомство с конструкторами и затронем тему прототипов.

Оглавление цикла уроков по функциям в javascript.

Добавить комментарий