И снова объекты!

 
0
 
JavaScript
ava
maxkazar | 11.10.2004, 12:05
Как сделать наследование в объектах JScript
Я попробывал сам и вот что получилось

function a()
{this.create = a_create}

function a_create()
{alert("a")}

function b()
{this.create = b_create}

b.prototype = new a()

function b_create()
{b.prototype.create()
alert("b") }

var oa = new a()
oa.create()

var ob = new b()
ob.create()


при выполнении скрипта получаем следующее


//Create объекта oa
a

//Cretae объекта ob
a
b


Вобщемто все работает (метод create наследуеться)... вот только мне не нравиться
что из метода необходимо сылаться через имя класса на метод класса

b.prototype.create()


естли какие предложения как сделать наследование красивым)
Comments (10)
ava
ElectricalStorm | 11.10.2004, 16:04 #
Цитата


естли какие предложения как сделать наследование красивым



есть

1. Вам надо хорошенько подумать над code style...
2. Смотри пример


function BaseClass(from, name) {
this.from = from || "author";
var name = name || "somebody";

// Приветствие.
this.hello = function() {
// закрытые свойства пишем без this
alert("Hello, "+name+", from "+this.from);
}

// Метод для установки значения закрытого свойства.
this.setName = function(n) {
name = n;
}

// Приватный метод
function privateMethod() {
alert("Private, "+name+", from "+this.from);
}
}

DerivedClass.prototype = new BaseClass();

function DerivedClass() {
this.helloDerived = function() {
alert("Hello from derived");
}
}

// Создаем объект базового класса и проверяем работу.
var obj = new BaseClass();
obj.setName("World");
obj.hello();

// Создаем объект производного класса и проверяем работу.
var objDerived = new DerivedClass();
objDerived.hello();
objDerived.helloDerived();

ava
Sardar | 11.10.2004, 21:54 #
Цитата (maxkazar @ 11.10.2004, 10:05)
Вобщемто все работает (метод create наследуеться)... вот только мне не нравиться что из метода необходимо сылаться через имя класса на метод класса

maxkazar код от начала и до конца правильный ;-)
Осталось только понять что конкретно происходит. В JS нет классов(мы пока не расматриваем JS2), это обьектно-прототипный язык. Это значит что все кроме примитивных типов есть обьекты, от обьектов порождаются другие обьекты, на практике создать обьект можно только от обьекта Function. У каждого обьекта есть конструктор - обьект функция, т.е. этот код:
var test=new myObject();
var test2=new test.constructor();

Создаст еще один обьект от myObject.
У функций есть свойство prototype, задающее интерфейс всем обьектам созданным от этой функции. Сказанное выше и это формирует понятие обьектно-прототипный язык. Тут есть несколько моментов:
  • если прототип функции не изменят присваиванием обьекта, а просто создавать/изменять его поля, то все изменения отражаются на всех обьектах, созданных от этой функции.
  • если полю prototype присвоили новый обьект, то все изменения над прототипом будут отражатся на созданых после обьектах и присвоенном обьекте. Обьекты созданные ранее изменения прототипа останутся не изменными.
Цитата (maxkazar @ 11.10.2004, 10:05)
естли какие предложения как сделать наследование красивым)

Я не знаю что ты считаешь красивым ;-) но тем не менее в JS есть и свои тараканы. Например следующий код:
function a(){
this.create = function(){this.bla="test";};
}
function b() {
this.create = function() {alert(this.constructor);};
}
b.prototype = new a()
var ob = new b()
ob.create();

Покажет нам что в this.constructor лежит ссылка на функцию a! Полнейший бред но это так(во всех браузерах), так что this.constructor.create(), как если бы b была бы нашим конструктором, ты не можешь. Так что тво способ верный и не стоит морочить себе голову :)

Кстати JS это очень гибкий, без жестких типов язык, что бы потребовалось наследование с переопредлением методов встречаю в первый раз ;-)
Пиши проще, для этого JS и придумывался, а наследование и типы оставь для Java.

Цитата
Вам надо хорошенько подумать над code style...

Странное замечание... ;-)
И еще заинтересовал пример с приватным методом, как и ожидал он не работает ;-)
На самом деле создается функция существующая в момент работы конструктора BaseClass, после его завершения функция уничтожается.
ava
ElectricalStorm | 12.10.2004, 09:48 #
Sardar мне кажется Вы что-то не допонимаете

Если взять за основу мой пример то становиться все понято


var test=new DerivedClass(); // создание обьетка
alert(test.toSource()); // посмотрим что это

// Это не создание обьекта !!! нет
// Это создание обьекта суперкласса !!!
var test2=new test.constructor();

alert(test2.toSource()); // посмотрим что это


и тогда абсолютно понятно почему вот такой пример работает правильно

function a(){
this.create = function(){this.bla="test";};
}

function b() {
this.create = function() {alert(this.constructor);};
}

b.prototype = new a()
var ob = new b()
ob.create();




Цитата


Странное замечание...



что здесь странного - очень коряво написаый код

Цитата


еще заинтересовал пример с приватным методом, как и ожидал он не работает



Еще как работает.
Эту функцию можно использывать внутри класса... так же как это делается во всех ОО языках
ava
Sardar | 12.10.2004, 19:56 #
Цитата (ElectricalStorm @ 12.10.2004, 08:48)
Sardar мне кажется Вы что-то не допонимаете

Если взять за основу мой пример то становиться все понято

Ваш код ни о чем не говорит и не понятно что вы считаете правильным. У меня не малый опыт с JS, если я считаю какую нибудь деталь не удобной, то и правильной я ее считать не буду. Другими примерами недочетов JS например может быть отсутствие методов поиска у массивов.

Я повторяю в JavaScript нет классов(супер кллассов и т.п.), потому как нет типов для обьектов. Поле constructor должно содержать ссылку на функцию породившую обьект, что и происходит до присваивания прототипу родительской функии левого обьекта. После присваивания constructor содержит ссылку на функцию, обьект которой мы присвоили в прототипе нашей родительской функции.
Я вижу это как недостаток, т.к. нельзя например вызвать метод из унаследованного обьекта, приходится использовать имя родительской функии(как это правильно сделал maxkazar), что не красиво. Если бы constructor не изменялся, то можно было бы легко поднятся по иерархии до унаследованного обьекта. Скорее всего это недоделка нетскаповцев.
Цитата (ElectricalStorm @ 12.10.2004, 08:48)
что здесь странного - очень коряво написаый код

Я попрошу вас в будущем воздержатся от таких высказываний. Тем более не обоснованных, они вас не украшают, скорее наоборот

Цитата (ElectricalStorm @ 12.10.2004, 08:48)
Еще как работает. Эту функцию можно использывать внутри класса... так же как это делается во всех ОО языках


Действительно работает, впрочем ни в одном учебнике такого не видел. Доказал чисто опытным путём.

Рассмотрим код:
function test() {
var a=90;
var b="test";
function incA(a) {
b="Vingrad";
return a++; //постинкремент, значение изменится после возврата
}
for(var i=0; i<10; i++) a=incA(a);
alert(a);
alert(b);
}
test();

Замечаем что фнутри вложенной функции нам доступны переменные из контекста выше(что было и раньше когда вы создавали функции в контексте window), переменные определенные в функции являются локальными, потому воздействие на a никак не отражется на a выше по контексту. Заменим a++ на a+1, получили требуемый результат.
Что же такое вложенная функция? После работы test мы не можем достигнуть incA: alert(window.incA+", "+test.incA);
На самом деле функция уничтожается вместе с контекстом test(), после того как та отработает. Вложенная функция incA это локальный обьект, как и любой другой обьект он должен уничтожится вместе с контекстом.

Рассмотрим что происходит при создании обьекта:
function test() {
var a=90;
var b="test";
function incA(a) {
b="Vingrad";
return a+1;
}
for(var i=0; i<10; i++) a=incA(a);
alert(a);
alert(b);

this.accessPrivate=function() {
alert(incA(200));
}
}
var t=new test();
alert(t.incA); //undefined
t.accessPrivate();

Оператор new создает новый контекст, и связывает его с this. Запускается функция, создается ее собственный контекст. Все вызовы/изменения с this воздействуют на контекст созданный оператором new. Обращение к функциям/переменным без this воздействует на контекст функции и высшие контексты. Значит функция incA создается в контексте функции, а этот контекст доступен внутри обьекта при обращении без this. То есть контексты: <window><test: incA><accessPrivate>выше по контексту incA, этот контекст никому не доступен, потому можно считать его приватным для нас</accessPrivate></test></window>.

ElectricalStorm спасибо за это уточнение.
ava
ElectricalStorm | 13.10.2004, 09:30 #
Цитата


повторяю в JavaScript нет классов(супер кллассов и т.п.), потому как нет типов для обьектов.



Вы утверждаете что ООП в javascript нет а я говорю что есть пересказывать мануал не буду
дам ссылку

http://www.codeproject.com/aspnet/JsOOP1.asp

ava
Sardar | 13.10.2004, 23:56 #
Цитата (ElectricalStorm @ 13.10.2004, 08:30)
Вы утверждаете что ООП в javascript нет

Я этого не утверждал, если у вас наличие классов ассоциируется только с ООП языками(что верно ;-) ), то вы заблуждаетесь на счет JavaScript. В JS нет типов и нет классов описывающих тип обьекта, мало того два обьекта порождённые одной функцией могут быть совершенно разными после некоторых модиффикаций над ними и тем не менее "принадлежать" родительской функции(instanceof->true). Поэтому приходится проверять наличие свойства у обьекта прежде чем его использовать. Наличие классов(типов) это большое преимущество при написании большого кода + легкое проектирование. Но JS изначально придумывался как простой скриптовый язык, классы здесь как козе баян. На JS можно писать как в директивном, так и в обьектном стиле, когда существуют обьекты сuществуйщие "сами по себе", когда большинство кода кода по созданию обьекта использует factory подход т.е. parentObject.createXXX(), parentObject.createYYY();

Не знал о возможностях инкапсуляции. Но это по сути сохранение контекста родительской функции и установка его выше по вложенности для обьекта, а я думал что контекст уничтожается. Обьекты продолжают быть хешьтаблицами с воможностью динамического создания/удаления полей, контексты это тоже хешьтаблицы.

2All советую прочесть статью, много полезного.
ava
maxkazar | 01.11.2004, 10:05 #
Столкнулся со следующей проблемой

Пробую сделать следующую иерархию
A
|
B
/ \
C D

ну в коде приблизительно следующие

function A() {
this.ShowTest = fnShowTest
var Test = Math.Random(100)

function fnShowTest() {
alert(ShowTest)
}
}

B.prototype = new A()
function B() {
}

C.prototype = new B()
function C() {
}

D.prototype = new B()
function D() {
}


Так вот, если мы сделаем два класса C и D и вызовем у них метод ShowTest то получим один и тотже результат. В принципе все верно, контекс объекта A создаеться один лишь раз для объекта B, соответсвенно и для C и D((((. Опять рушиться обектный подход(((. Что делать и как быть? Ломаю голову не первый день.
ava
Sardar | 01.11.2004, 11:13 #
Цитата (maxkazar @ 1.11.2004, 09:05)
В принципе все верно, контекс объекта A создаеться один лишь раз для объекта B, соответсвенно и для C и D((((. Опять рушиться обектный подход(((


Где рушится? Наследование не может урезать интерфейс, только расширить ;-) В наследниках C и D имеем все от B, который в свою очердь унаследовал интерфейс от A. Что по твоему не верно?
ava
maxkazar | 01.11.2004, 11:30 #
Получаеться что пременая Test будет одна для объектов C и D т.е. если я изменю значение Test в объекте D то и изменится значение Test в объекте C!!!(((. А это неправильно
ava
Sardar | 01.11.2004, 14:07 #
Цитата (maxkazar @ 1.11.2004, 10:30)
если я изменю значение Test в объекте D

Переменная Test является приватной и принадлежит только А, никакими способами кроме интерфейса А ты на переменную воздействовать не можешь. В JavaScript нет классов, т.е. нет наследования от класса(от типа) как например в C++ или Java. То есть нет понятия: при создании обьекта вначале автоматом создаются все его предки.
В JavaScript есть только обьекты, порожденные некоторой функцией и имеющие интерфейс создаваемой этой функцией + интерфейс обьекта в прототипе(изначально прототип это пустой обьект). Обьект в прототипе не копируется! Значит это верно что все обьекты наследуемые B имеют одинаковые переменные A созданной для B.

А все потому что JavaScript это не Java, это обьектно прототипный язык, позволяющий писать как в директивном так и в ООП стиле. Это идеально для не больших скриптов, которыми скрипты в страничке и являются. Ты просто представь себе огрменные библиотеки классов для создания roll over эффекта :D

P.S. я пишу на JS, QVB и нa Java - все три языка относятся к различным парадигмам smile
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
advanced
Submit