- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Основы программирования на JavaScript - Марк Кан
Шрифт:
Интервал:
Закладка:
Синтаксис этого метода немного отличается от предыдущего. Вместо объявления всех свойств и методов внутри функции Cat, они теперь объявляются с помощью Cat.prototype. Это может показаться более сложным, но предлагает много преимуществ. Предположим, например, что надо добавить новую функцию sleep для каждого имеющегося cat. Это можно сделать двумя способами. Первый: можно добавить функцию sleep в felix, sam и patty. Это, однако, не только трудоемко, но также и неэффективно. Если бы имелось 500 cat, то потребовалось бы сначала отследить всех этих 500 котов, а затем добавить функцию каждому cat.
Однако с помощью прототипов можно добавить функцию sleep всем cat одновременно:
Cat.prototype.sleep = function(){ alert(this.name+' falls asleep'); };
Этот способ не только быстрее, но к тому же нам больше не требуется отслеживать каждого cat, чтобы добавить функцию sleep.
Существует более быстрый способ добавления прототипов. С помощью объектного литерала можно одновременно задать любое количество прототипов свойств или методов.
function Cat(name){ this.name = name; } Cat.prototype = { species: 'Cat', talk: function(){ alert('Meow!'); }, callOver: function(){ alert(this.name+' ignores you'); }, pet: function(){ alert('Pet!'); } }
Важно отметить, что с помощью этого метода можно задать свойства функции только один раз. После этого необходимо использовать предыдущий метод.
Object.prototype.method = function(){ ... }.
Если попробовать теперь добавить в cat метод sleep с помощью этого метода:
Cat.prototype = { sleep: function(){ alert(this.name+' falls asleep'); } }
то предыдущие прототипы, species, talk, callOver и pet, будут все удалены. Единственным имеющимся прототипом для cat будет sleep.
Прототипы можно также использовать для расширения встроенных объектов JavaScript. Можно реализовать, например, функцию String.prototype.reverse, которая будет возвращать любую созданную строку в обратном порядке:
String.prototype.reverse = function(){ var out = ''; for(var i=this.length-1; i>=0; i--){ out+=this.substr(i, 1); } return out; } alert('asdf'.reverse());
Это может быть очень полезным инструментом при правильном использовании. Можно реализовать String.prototype.trim() для удаления из строки всех пробелов, Date.prototype.dayName - для получения названия дня недели из объекта Date и т.д. Однако настоятельно рекомендуется воздержаться от добавления каких-либо прототипов в Array или Object, так как в этом случае циклы for-in для двух этих типов данных будут работать неправильно. Рассмотрим следующий пример:
var myArray = [1, 2, 3]; for(n in myArray) alert(n); // выводит 0, 1 и 2 - индексы массива. Array.prototype.something = function(){ }; for(n in myArray) alert(n); // выводит 'something', 0, 1 и 2.
Как можно видеть, здесь выполнено прототипирование Array и добавлена функция something. Однако теперь эта функция something видна как элемент массива, результат, который определенно не ожидался и не требовался. То же самое происходит с объектами и объектными литералами, если выполнить прототипирование Object. Если можно быть абсолютно уверенным, что цикл for-in никогда не будет использоваться и никакой другой разработчик не будет использовать этот код JavaScript, то можно применять прототипирование для Array или Object, но надо помнить о связанных с этим проблемах. Однако существуют другие методы для достижения тех же результатов. Например, для расширения Array можно задействовать следующий метод без прототипирования:
Array.find = function(ary, element){ for(var i=0; i<ary.length; i++){ if(ary[i] == element){ return i; } } return -1; } alert(Array.find(['a', 'b', 'c', 'd', 'e'], 'b')); // выводит 1
Как можно видеть, теперь необходимо печатать Array.find(ary, e) вместо ary.find(e), что пришлось бы делать, если прототипировать объект Array, но стоит напечатать эти несколько дополнительных символов, чтобы избежать потери существующей функциональности JavaScript.
Способ определения переменных в объекте определяет, какие методы этого объекта можно использовать для доступа к этим переменным. В JavaScript при работе с объектно-ориентированным кодом используется пять уровней методов и свойств.
1 Скрытая (Private) - объявляется с помощью var variableName или function functionName внутри объекта. Могут быть доступны только другим скрытым или привилегированным функциям.
2 Открытая (Public) - объявляется с помощью this.variableName внутри объекта. Может изменяться любой функцией или методом.
3 Привилегированная (Privileged) - объявляется с помощью this.functionName = function(){ ... } внутри объекта. Доступна для любой функции или метода и может обращаться или изменять любую скрытую переменную.
4 Прототипированная (Prototype) - объявляется с помощью Class.prototype.variableName или Class.prototype.functionName. Объявленные таким образом функции будут иметь доступ к любой открытой или прототипированной функции. Попытки изменить созданную таким образом переменную будут вместо этого создавать новую открытую переменную на объекте, а прототипированная переменная будет недоступна.
5 Статическая (Static) - объявляется с помощью Class.variableName или Class.functionName. Может изменяться любой функцией или методом. Такой метод используется редко.
Чтобы понять различия между уровнями, давайте рассмотрим пример:
function Cat(name, color){ /* Конструктор: при создании объекта выполняется любой находящийся здесь код */ Cat.cats++; /* Скрытые переменные и функции доступны только скрытым или привилегированным функциям. Отметим, что 'name' и 'color', переданные в Class, уже являются скрытыми переменными. */ var age = 0; var legs = 4; function growOlder(){ age++; } /* Открытые переменные доступны открыто или скрыто */ this.weight = 1; this.length = 5; /* Привилегированные функции доступны открыто или скрыто. Могут обращаться к скрытым переменным. Невозможно изменить, можно только заменить открытой версией */ this.age = function(){ if(age==0) this.length+=20; growOlder(); this.weight++; } } /* Прототипированные функции доступны открыто */ Cat.prototype = { talk: function(){ alert('Meow!'); }, callOver: function(){ alert(this.name+' ignores you'); }, pet: function(){ alert('Pet!'); } } /* Прототипированные переменные доступны открыто. Нельзя перезаписать, только заменить открытой версией */ Cat.prototype.species = 'Cat'; /* Статические переменные и функции доступны открыто */ Cat.cats = 0;
Мы видим, что существует несколько уровней доступа. Как было сказано ранее, все скрытые, привилегированные и открытые функции и переменные копируются всякий раз, когда создается новый экземпляр объекта. Обычно почти все, что нужно сделать, можно реализовать с помощью прототипированных и открытых переменных. В связи с этим обычно лучше избегать использования скрытых, привилегированных и статических переменных, если это не требуется специально.
Лекция 9. Наследование и замыкание
Метод наследования. Полезные (и опасные) свойства замыкания.В восьмой лекции были рассмотрены основы объектно-ориентированного программирования в JavaScript. В данной лекции эта тема будет продолжена рассмотрением методов наследования, а также полезных (и опасных) свойств замыкания.
В предыдущей лекции была создана функция 'Cat' :
function Cat(name){ this.name = name; } Cat.prototype = { species: 'Cat', talk: function(){ alert('Meow!'); }, callOver: function(){ alert(this.name+' ignores you'); }, pet: function(){ alert('Pet!'); } }
Теперь можно создать любое количество котов, но как быть, если мы захотим создать объект другого типа, например, собаку? В этом случае понадобится создать совершенно новую функцию, со своими собственными прототипами. Если два объекта используют одни и те же функции (например, можно было бы добавить функции sleep (спать), eat (есть), и play (играть)), то в результате мы бы имели чрезмерное дублирование кода. Решением является концепция наследования.
По сути наследование позволяет определить объекты "предки" и "потомки". Потомок наследует все свойства своего предка. Можно было создать, например, функцию Animal, Pet или Mammal. Обе функции Cat и Dog обладали бы многими свойствами функции предка Animal, и нам пришлось бы писать этот код один раз.
Проблема в том, что JavaScript не имеет в действительности встроенного механизма наследования, поэтому эту функциональность необходимо создавать самостоятельно. Для этого существует несколько различных способов. Один из них состоит в использовании функции call. Эта функция позволяет вызывать одну функцию из контекста другой, т.е. мы можем определить, как действует ключевое слово this. С помощью call можно написать класс Animal (Животное), а затем вызвать его из класса Cat или Dog.