Модераторы: Sardar, Aliance
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> ООП в JavaScript - эмуляция классов, наследования, Помогите найти подводные камни 
:(
    Опции темы
Replicator
Дата 4.6.2007, 20:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 30.4.2006
Где: Outer Heaven

Репутация: нет
Всего: нет



Написал тут такой код:
Код

//**************************************************************************
//                                Class
//**************************************************************************
/**
 * Create new class, which can have constructor (method named
 * initialize)
 */
function Class() {

    //function which makes new class to have constructors
    function proto() {

        //if there is constructor, then call it
        if (this.initialize) {
            this.initialize.apply(this, arguments);
        }
    }

    //create variable of object with initializerss
    var child = proto;


    switch (arguments.length) {
        case 1:

            //make child's prototype
            child.prototype = arguments[0];
        break;

        case 2:

            //inherit from parent
            child.prototype = new arguments[0];

            //add new fields
            for (field in arguments[1]) {
                child.prototype[field] = arguments[1][field];
            }
        break;
    }


    //return new object it
    return child;
}
///////////////////////////////////////////////////////////////////////////

В двух словах, код эмулирует классы. На мысль меня навела библиотека prototype, но мне их эмуляция показалась не совсем завершенной. Теперь новый класс (объект) можно создать так:
Код

    //create new class "from zero"
    var Engine = new Class({
        cubic: 0,

        //constructor
        initialize: function(cubic) {
            this.cubic = cubic;
        }
    })

Наследование осуществляется так:
Код

    //create the class which extends Engine
    var Car = new Class(Engine, {
        model: 'Audi',
        season: 'Winter',
        speed: 300,

        //override constructor
        initialize: function(cubic, serial) {
            this.cubic = cubic;
            this.model += ' ' + serial;
        },

        go: function() {
            alert('Running: ' + this.speed + ' km/h');
        }
    })

Вот именно из-за наследования я и начал писать эту библиотеку. По-моему, так гораздо проще и понятней наследовать классы (объекты). По крайней мере, для тех, кто перешел из традиционных ООП-языков.

Но вот что меня интересует. Может, при таком "изврате" появляются какие-нибудь подводные камни. Пока их не видно, но когда начну что-нибудь мутить с прототипом, камни могут всплыть. Помогите потестить код и найти камни. А может, сразу косяк какой в глаза бросается?

Ниже привожу полный код для тестирования.
Код

    //create new class "from zero"
    var Engine = new Class({
        cubic: 0,

        //constructor
        initialize: function(cubic) {
            this.cubic = cubic;
        }
    })

    //create the class which extends Engine
    var Car = new Class(Engine, {
        model: 'Audi',
        season: 'Winter',
        speed: 300,

        //override constructor
        initialize: function(cubic, serial) {
            this.cubic = cubic;
            this.model += ' ' + serial;
        },

        go: function() {
            alert('Running: ' + this.speed + ' km/h');
        }
    })

    //add new field to the prototype of base object
    Engine.prototype.code = 'XTZ2100';

    //create object of cless Car
    var myCar = new Car(500, 100);


    //show all public fialds of object myCar
    var test = 'myCar = Object {\n';
    for (var m in myCar) {
        test += m + ': ' + myCar[m] + '\n\n';
    }

    test += '}\n\n';

    //test if Engine and Car are prototypes of myCar
    test += 'Engine is prototype of myCar: ' + Engine.prototype.isPrototypeOf(myCar) + '\n';
    test += 'Car is prototype of myCar: ' + Car.prototype.isPrototypeOf(myCar) + '\n\n';


    //test if myCar is instance of Car and Engine
    test += 'myCar is instance of Car: ' + (myCar instanceof Car) + '\n';
    test += 'myCar is instance of Engine: ' + (myCar instanceof Engine);

    //display results
    alert(test);
}

--------------------
 
PM WWW ICQ   Вверх
ksnk
Дата 5.6.2007, 07:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 84
Всего: 386



Посмотрите еще в набла 40 - Наследование в JavaScript. В конце статьи приведен код класса, содержащего, в отличии от вашего нормальную реализацию конструкторов объектов, а не один на пучек, как у вас




--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
vasac
Дата 5.6.2007, 09:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: 13
Всего: 36



Граждане, прекратите эмулировать то, чего нет в языке и чему есть достойная замена.
PM WWW   Вверх
Replicator
Дата 5.6.2007, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 30.4.2006
Где: Outer Heaven

Репутация: нет
Всего: нет



Цитата(ksnk @  5.6.2007,  07:53 Найти цитируемый пост)
Посмотрите еще в набла 40 - Наследование в JavaScript. 

Спасибо. Нужно будет добавить определение поля constructor, а то оно, действительно, не соответствует. Кроме того, я подумал, что создавать объекты можно просто вызовом функции:

Код

var class_ = Class({
    //define fields
})


без new. Так логичнее, по-моему.
--------------------
 
PM WWW ICQ   Вверх
Zeroglif
Дата 5.6.2007, 12:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 644
Регистрация: 22.9.2005

Репутация: 28
Всего: 66



Цитата(Replicator @  5.6.2007,  11:59 Найти цитируемый пост)
Кроме того, я подумал, что создавать объекты можно просто вызовом функции

Если внутри Class не нужен будет this и из неё вернётся руками созданный объект, то можно и без new.
PM MAIL WWW   Вверх
Replicator
Дата 5.6.2007, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 30.4.2006
Где: Outer Heaven

Репутация: нет
Всего: нет



Вот переделанный вариант:
Код

//**************************************************************************
//                                Class
//**************************************************************************
/**
 * Create new class, which can have constructor (method named
 * initialize)
 */
function Class() {

    //function which makes new class to have constructors
    var child = function() {

        //prevent constructor to run while "class" creation
        if (child.__preparing) {
            delete(child.__preparing);
        } else {

            //if there is constructor, then call it
            if (this.initialize) {
                this.initialize.apply(this, arguments);
            }
        }
    }


    //choose action to perform: 1. create class from zero or 2. extend class
    switch (arguments.length) {
        case 1:

            //make child's prototype
            child.prototype = arguments[0];
        break;

        case 2:

            //set flag which tells not to run constructor right now
            arguments[0].__preparing = true;

            //inherit from parent and set proper constructor
            child.prototype = new arguments[0];
            child.prototype.constructor = arguments[0];

            //add new fields
            for (field in arguments[1]) {
                child.prototype[field] = arguments[1][field];
            }
        break;
    }


    //return new object it
    return child;
}
///////////////////////////////////////////////////////////////////////////

Вот код для тестирования:
Код

function test() {

    //create new class "from zero"
    var Engine = Class({
        cubic: 0,

        //constructor
        initialize: function(cubic) {
            this.cubic = cubic;
        }
    })

    //create the class which extends Engine
    var Car = Class(Engine, {
        model: 'Audi',
        season: 'Winter',
        speed: 300,

        //override constructor
        initialize: function(cubic, serial) {
            this.cubic = cubic;
            this.model += ' ' + serial;
        },

        go: function() {
            alert('Running: ' + this.speed + ' km/h');
        }
    })

    //add new field to the prototype of base object
    Engine.prototype.code = 'XTZ2100';

    //create object of cless Car
    var myCar = new Car(500, 100);


    //show all public fialds of object myCar
    var test = 'myCar = Object {\n';
    for (var m in myCar) {
        test += m + ': ' + myCar[m] + '\n\n';
    }

    test += '}\n\n';

    //test if Engine and Car are prototypes of myCar
    test += 'Engine is prototype of myCar: ' + Engine.prototype.isPrototypeOf(myCar) + '\n';
    test += 'Car is prototype of myCar: ' + Car.prototype.isPrototypeOf(myCar) + '\n\n';

    //test if myCar is instance of Car and Engine
    test += 'myCar is instance of Car: ' + (myCar instanceof Car) + '\n';
    test += 'myCar is instance of Engine: ' + (myCar instanceof Engine) + '\n\n';


    //display results
    alert(test);
}

А вот код для тестирования из набла 40 - Наследование в JavaScript, немного переписанный для тестирования моего объекта:
Код

<pre><script type="text/javascript">//<![CDATA[

// Базовый "класс".
var Car = Class({
  initialize: function() {
    document.writeln("Вызван конструктор Car().");
  },
  drive: function() { 
    document.writeln("Вызван Car.drive()"); 
  }
});

// Производный "класс".
var Zaporojets = Class(Car, {
  initialize: function() {
    document.writeln("Вызван конструктор Zaporojets().");
    this.constructor.prototype.initialize.call(this);
  },

  crack: function() { 
    document.writeln("Вызван Zaporojets.crack()");
  },

  drive: function() { 
    document.writeln("Вызван Zaporojets.drive()");
    return this.constructor.prototype.drive.call(this);
  }
});

document.writeln("Программа запущена.");

// Создаем объект производного "класса".
var vehicle = new Zaporojets();
vehicle.drive(); // вызывается функция базового объекта

// Создаем еще один объект того же класса.
var vehicle = new Zaporojets();

vehicle.crack(); // функция производного объекта
//]]></script></pre>

Что я исправил:
  • теперь возможен вызов полей родительского объекта,
  • вызовы конструкторов теперь происходят как и в традиционных ООП-языках (спасибо набле),
  • класс создается вызовом функции, т.е. без new (а оно и раньше так работало - это я ступил).

--------------------
 
PM WWW ICQ   Вверх
dmage
Дата 21.6.2007, 00:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 21.6.2007

Репутация: нет
Всего: 1



Цитата(vasac @ 5.6.2007,  09:20)
Граждане, прекратите эмулировать то, чего нет в языке и чему есть достойная замена.

А что является достойной заменой наследования в JavaScript? smile 
PM MAIL   Вверх
vasac
Дата 21.6.2007, 09:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: 13
Всего: 36



Я не про наследование. Наследование в JS есть.
Я про эмуляцию класс-ориентированного подхода средствами прототипно-ориентированного языка.
PM WWW   Вверх
AlDev
Дата 7.9.2007, 08:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный идиотъ
***


Профиль
Группа: Участник Клуба
Сообщений: 1927
Регистрация: 17.4.2005
Где: Irk, rus

Репутация: нет
Всего: 50



Replicator
К сожалению не все так хорошо.
Пример теста:
Код

                    var A = Class({
                        initialize: function() {
                            alert ('A!');
                        }
                    })

                    var B = Class(A,{
                        initialize: function() {
                            alert ('B!');
                            this.constructor.prototype.initialize.call(this);
                        },

                        testMethod: function() {
                            alert ('йа тестег!');
                        }
                    })

                    var C = Class(B,{
                        initialize: function() {
                            alert ('C!');
                            this.constructor.prototype.initialize.call(this);
                        },

                        //override testMethod
                        testMethod: function() {
                            //undefined
                            this.constructor.prototype.testMethod();
                        }
                    })

                    var t = new C();
                    t.testMethod();

родительский testMethod - undefined.
Что в Вашем коде, что в набле.
PM MAIL WWW ICQ YIM MSN   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Форум для вопросов, которые имеются в справочниках, но их поиск вызвал затруднения, или для разработчика требуется совет или просьба отыскать ошибку. Напоминаем: 1) чётко формулируйте вопрос, 2) приведите пример того, что уже сделано, 3) укажите явно, нужен работающий пример или подсказка о том, где найти информацию.
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | JavaScript: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1021 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.