Веб-разработка

индекс
236,88

Наследование в JavaScript (хабрасеминар)

Недавно в Хабре я хотел прочитать небольшой доклад об объектной ориентации и наследовании классов в JavaScript.

Объектно-ориентированный Java Script



Дело в том, что в свое время я был в полном восторге, научившись создавать свои собственные объекты и выстраивать цепочки наследования, и решил, что называется, поделиться с другими своими находками и наблюдениями. (=

Признаюсь, что в процессе подготовки текстов семинара некоторые вещи я открыл для себя заново и был вновь удивлен теми возможностями, которые JavaScript имеет в своем распоряжении, и которые становятся доступными разработчику лишь при пристальном разглядывании и экспериментировании языком.

Пользуясь тем, что семинар все время откладывается «до следующей пятницы», я решил опубликовать тексты семинара в сети, дабы мои восторги оказались полезными еще кому-нибудь. Итак:



ООП в Java Script (1): Объекты


В быстром темпе дается понимание того, что все в JavaScript по сути есть объект. Поэтому не странно выглядит следующая конструкция:
var f = function(){ // создаем новый метод f объекта window (window.f) 
	alert(this == window); // выводит true
}
f(); // вызываем метод f объекта window (window.f())

f.m = function(){ // создаем новый метод m объекта window.f (window.f.m)
	alert(this == f); // выводит true
}
f.m(); // вызываем метод m объекта window.f (window.f.m())


ООП в Java Script (2): Классы


Введение в понятие класса в JavaScript. Разбор таких базовых понятий как .constructor и .prototype

// Функция-конструктор - это обычная функция
var Class = function(p){
	alert('My name is constructor');
}


var s = 'karaboz';
s.constructor.prototype.tell = function(){
	alert(this);
}
s.tell(); // выводит 'karaboz'


ООП в Java Script (3): Свойства и методы класса


Обзор методов и свойств класса: члены класса могут быть открытыми (public), закрытыми (private), привилегированными (privileged) и статическими (static). Понятие замыкания (closure)

ООП в Java Script (4): Наследование классов


В JavaScript нет встроенной поддержки наследования (как собсвенно нет в нем и классов). Однако наследование можно реализовать (эмулировать) вручную, пользуясь услугами свойства .prototype.
Эта, заключительная часть семинара, повествует о тех опасностях, которые подстерегают любого разработчика, дерзнувшего реализовать полноценное наследование в JavaScript. В конце повествования все оказывается хорошо, и мы с удовольствием преодолеваем все трудности (=
+17
26 октября 2007, 04:33
70

комментарии (54)

0
heoh #
очень интересно, спасибо ))
0
otaqsun #
Изложение своеобразное у тебя) но полезность бесспорна)
0
theOnlyBoy #
Хвалю, хорошо написано (ну, за исключением мелких помарок).
Да и оформлено отлично, приятно.
0
gro #
Про добавление метода примитивному значению.
Это ограничение, наложенное JavaScript на переменные (объекты), созданные через строковые,

Это не ограничение, это запаковка примитива в объект.

var srt1 = "Литерал";
str1.tell = "Свойство";

При попытке доступа к свойству (как получения, так и установки) примитивного значения, создается объект, соответствующий этому примитиву и работа продолжается с ним. После нужных действий он удаляется. Значение же самой изначальной переменной не затрагивается.
0
gro #
В JavaScript нет встроенной поддержки наследования (как собсвенно нет в нем и классов). Однако наследование можно реализовать (эмулировать) вручную, пользуясь услугами свойства .prototype.

В javascript есть полноценное встроенное наследование — наследование на основании цепочки прототипов. Если не пытаться подогнать JS-парадигму под более привычную большинству (с классами), то и эмулировать ничего не нужно.
0
karaboz #
Все таки, я бы не стал так смело говорить о существовании в JS "наследования на основании цепочки прототипов". Да конечно, наследование мы строим, пользуясь этой "всемогущей цепочкой", однако для этого приходится изрядно попотеть - например для того, чтобы решить две важнейшие проблемы:
1. конструктор надкласса не должен вызываться еще до создания объекта подкласса
2. методы надкласса не должны перезаписываться одноименными методами подкласса

Если же пользоваться .prototype напрямую, как в книжках написано (да хоть в тойже "Javascript: The Definitive Guide, By David Flanagan"), то ничего не получится и более или менее интересных вещей реализовать не удастся
+2
gro #
Интересные вещи реализуются просто и безболезненно :) Только нужно понять саму суть JS-парадигмы и полюбить её )
Конструктор надкласса не должен вызываться до создания объекта подкласса, по одной только причине — тут не должно быть никаких "надклассов" и "подклассов". Есть только объекты. Чистые и незамутненные :-D
0
karaboz #
а пояснить не можете? по поводу чистых и незамутненных! (= может ссылкой какой-нибудь? (=

дело в том, что когда я залез в разные модные js библиотеки, то не нашел там нормальной реализации наследования =( Везде этот метод .extend, который тупо копирует свойства и методы родителя, а не пользуется этими методами напрямую. Вот в prototype.js только в последней версии кажется была предпринята попытка сделать наследование с человеческим лицом.

Не о таких вы говорите объектах? (=
0
gro #
Больших знатоков JS тут же минусовали на Хабре, после того, как они осмеливались высказать своё мнение о "модных js-библиотеках", в том числе и о prototype.js. Так что я промолчу, тем более знаток я не такой большой.
Единственное, эти библиотеки отнюдь не то, на чем нужно позновать суть JS.
"Наследование", в своей основе, если отрешиться от всех реализаций и тому подобного, это всего лишь удобный способ строить похожие объекты на основании существующего шаблона. По сути еще одна ипостась повторного использования кода и ничего больше.
Через связь с объектом-прототипом мы получаем доступ (наследуем) к определенном в нем данным и функциям. Вот и всё наследование.
0
gro #
Опять начинаются главные огрехи подобных статей:
1. Говорить о классах, там где их нет. Да, вы их будете эмулировать, но об этом нужно сразу сказать читателю.
2. Начинать рассказ о сути ООП с технических деталей, типа, конструкторов, относящихся только к одному этапу - созданию объекта.
Самая суть ООП в JS, да и еще много чего в JS — цепочка областей видимости, это бы подробно для новичков и описать.
0
karaboz #
Да, суть и необходимость ООП в JS необходимо всякий раз прояснять, это точно, надо дорабатывать семинар (=
Однако простите, не понял, что вы имеете в виду под "Говорить о классах, там где их нет"?
0
gro #
Всё о том же. В JS нет классов. В перемешали вместе понятие "класс" и "прототип".
0
develop7 #
В JS классов нет. И не было никогда. Есть только объекты. Math - объект, String - объект, Array - объект. Вообще все есть объект, не являющийся экземпляром никакого класса.
Если Вы, скажем, "создали экземпляр" класса SomeClassLikeObject [var s = new SomeClassLikeObject()], то, будь это действительно класс, Вам бы не удалось выполнить что-нить вроде s.newMethod = function(arg){alert('this method does not exist in original "class"');};
Данный код вполне успешно выполняется и в результате получается, что s уже не экземпляр SomeClassLikeObject, так как в нем присутствует дополнительный метод.
0
gro #
Опять-таки что считать "классами" :)
Например, в PHP тоже, кажется, "классическое" ООП и классы, как у людей. Однако, объекту можно добавить новое свойство.
0
develop7 #
Ну, ООП в PHP классическим только считается (особенно в 4й версии). Подобные хаки, будучи преподнесенными, как достоинства, и использованными по назначению, до сих пор взрывают моск проблемами типа "ну вот, $%#$#, и откуда тут взялось это &^#$^%$# поле???".
0
gro #
А это не хак, уверяю вас :)
Просто нужно понимать как всё работает и "откуда взялось это поле".
ООП в PHP вполне годится, чтобы на средних проектах работать в ООП-стиле со всеми его преимуществами. А вся эта высокая болтовня о "стандартах ООП" и другом, дело десятое.
0
develop7 #
я под впечатлением пребывал от одного проекта, над которым в свое время работал. вот там фаршировка экземпляра класса полями в рантайме применялась на каждом шагу. И, уверяю Вас, я понимал и понимаю, как оно работает, но вот поиск ошибок и отладка при таком раскладе превращалась в сущий кошмар. Вот там-то моск и взрывало.
0
gro #
Ну, то что на языке можно писать отстойно, не значит, что нельзя лучше :)
0
develop7 #
fault-finding mode on
новое поле ;)
fault-finding mode off
+1
karaboz #
Все это ж называется динамическими классами. Т.е. классами, в объекты которых можно "налету" добавлять новые свойства и методы, не опредленные в самом конструкторе. Разве нет? (=
0
develop7 #
да нет... да и первый раз такое определение слышу.
Вот, нашел -
В итоге в языке Self были реализованы следующие концепции:
...
* отсутствие классов; такие языки называются prototype-based; в них создание новых типов объектов осуществляется посредством клонирования имеющихся и внесения изменений непосредственно в структуру нового объекта...
[skipped]

Отсюда
Типичные симптомы JavaScript'a. ;)
0
gro #
Упущена важная часть в описании .consturctor и .prototype.
Объекты связаны с прототипами внутренним свойством [[prototype]], которое невозможно изменить и в большинстве реализаций даже получить.
А не по цепочке obj.constructor.prototype.
Многие пытаются по этой цепочки дойти до корневого объекта или даже динамически изменить прототип объекта и очень удивляются, когда не получается.
0
dienow #
А как всё-таки дойти до корневого объекта если [[prototype]] не доступно?
0
magicstream #
статья хорошая.
типа "я напомню :), а дальше вы и сами разберётесь"
пару ссылок на тематические статьи не помешало бы.
например
- для новичков не совсем ясно как объявлять private или public элементы класса
- как именно делать наследование.
конечно есть гугл, но всё таки.
0
karaboz #
а как же - простите - ссылки имеются в нормальном количестве (=
ООП в JavaScript (5): Полезные ссылки
0
magicstream #
ой. простите. не заметил. забираю слова назад :)
0
arty #
classes are poor man's closures ©
; )
0
uint #
Похоже на реферат статей Котерова :)
+1
karaboz #
нет, это конечно же реферерат, но из разных источников, и потом я пользовался собственной логикой изложения (исходя из собственного опыта понимания этого всего) (=
0
develop7 #
Нет здесь Котерова и близко. У Дмитрия говорится - "классов нет, есть только объекты" и "наши классы - эмуляция настоящих".
0
wIliam #
есть js-библиотеки, позволяющие описывать классы, цепочки наследования и интерфейсы. вот например одна из вариантов http://forum.agiledev.ru/index.php?t=msg&th=995
+1
gro #
Ну вообще автор не библиотеку писал, а пытался донести основы механизмов.
0
gro #
А, почему, кстати, не в блоге JavaScript?
+1
karaboz #
не нашел такого блога ((=
+1
gro #
0
hannimed #
Извините, а что тут нового относительно тех же наблов? Помоему наблы 38-40 это всё прекрасно освящают. Их не читал только самый ленивый.
0
gro #
К сожалению, не совсем прекрасно.
Гораздо прекрасней освящают комментарии к ним.
0
hannimed #
например?
0
gro #
Почитайте комментарии к этим статьям. Особенно, к статье о наследовании.
0
hannimed #
Почитал, на первых страницах ДК говорит о том чтобы читали внимательней наблу, а потом жуткий оффтоп...
0
gro #
Среди этого офтопа изредка рассыпаны крупицы знания )
Особенно в постах Zeroglif'а.
Так же далеко не здорово написана набла по замыканиям с попытками связать с Перлом.
0
hannimed #
Согласен, с перлом я бы связывать не стал.
Вообще Вы правы, нет ни одной статьи об ООП в JS, в которой было бы всё прекрасно.
Лично мои знания в этой области основаны на совокупности многих статей и личного опыта.
А интерес к этой тематики возбудили именно наблы.
0
gro #
А мой интерес во многом комментарии к ним :)
+1
sphere #
Недописано.
http://disaen.com/misc/inheritance/
0
gro #
Какое множественно наследование?
__proto__ только для FF и то далеко не всегда.
0
sphere #
__proto__ в статье используется только для демонстрации доводов. Всё остальное делается стандартными средствами. Почитайте, пожалуйста, чуть внимательнее :)
0
gro #
Перечитал. Да, действительно:
По стандарту оно недоступно для просмотра и редактирования, но, к счастью, Firefox любезно предоставляет к нему доступ через __proto__

извините.

Но множественного наследования всё равно не увидел.
0
sphere #
Несогласованность термина. Убрал, чтобы не смущало.
+1
Zeroglif #
В общем и целом - ясная и доходчивая статья. Дописывайте, линкуйте к хабру, будем сглаживать шероховатости. ;)
0
sphere #
Спасибо за помощь, как карма позволит — выложу.
0
gro #
Теперь позволяет?
0
sphere #
Ога, спасибо :)
0
Pilat #
0
ISkomorokh #
Спасибо большое, очень полезно!

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