26 августа 2009 в 13:08

Полноценные классы в Javascript

К сожалению, в своей практике освоения Javascript мне не приходилось встречать толковой реализации классов и механизмов наследования. Хотя сам язык достаточно гибок и имеет огромный потенциал. Не доводилось видеть и удобной организации приватных методов. Обычно для этого использую следующий трюк. В качестве приватного метода создают функцию прямо в конструкторе, где должны быть описаны и все методы использующие её:
function MyClass() {
  function privateMethod() {
  }
  this.publicMethod = function() {
    // используем privateMethod();
  }
}
Данный подход имеет недостатки, поскольку privateMethod в указанном примере грубо назвать «методом класса». Все публичные методы приходиться описывать прямо в конструкторе, а значит, они будут создаваться каждый раз при создании нового объекта.
Также невозможно вне конструктора дополнить класс новыми методами.

Хочу предложить собственный механизм реализации классов в Javascript и поделиться с хабро-сообществом одной своей библиотекой — jsOOP.
Библиотека позволяет создавать неймспейсы и классы, наследовать их, добавлять методы и события с определенным уровнем доступа (public, private, protected) и дарит прочие вкусности объектно-ориентированного программирования.

Итак, подробнее о библиотеке.

Сразу приведу пример создания класса:
// объявляем класс A
jsOOP.createClass('A')

// задаем классу синоним
.alias('classA')

// задаем опции по умолчанию, они будут переданы конструктору
.options({
    a: 1
})

// объявляем конструктор
.constructor(function(op) {
    this.log('Call constructor A::A()')
        .log(op) // вывести опции, переданные в качестве аргумента
})

// определяем публичный метод log()
.method('log', function(s){
    сonsole.log(s);
    return this;
})

// добавляем приватный метод fprv()
.privateMethod('fprv', function(){
    return this.log('Call public method A::fprv()')
})

// определяем защищенный метод fptc()
.protectedMethod('fptc', function(){
    return this.log('Call protected method A::fptc()')
                .fprv() // вызываем приватный метод
})

// еще один публичный метод fpub()
.publicMethod('fpub', function(){
    return this.log('Call public method A::fpub()')
                .fptc() // вызываем защищенный метод
})


Объявление класса


Определение нового класса осуществляется очень просто: jsOOP.createClass(«A»). В результате создается класс A в пространстве jsOOP. Класс теперь доступен как jsOOP.A (полный путь), или просто — A. Плюс ко всему, мы добавили синоним классу — classA.
Функция createClass() возвращает ссылку на класс и дальше мы можем продолжать работать с ним: добавлять синонимы, определить конструктор, методы и прочее.

Конструктор


Конструктор определяется при помощи функции constructor(fn). В качестве параметра передается функция, которая будет выполняться при создании экземпляров класса.

Опции


Опции это специальный объект, который передается конструктору при инициализации экземпляра класса. В описании класса при помощи options() мы указали опции по умолчанию. Они могут быть весьма полезны в качестве именованных параметров для конструктора. В дальнейшем доступ к опциям внутри класса можно получить при помощи приватного метода _options().
this._options()     // -> {a:2} возвращает опции объекта
this._options('a')    // -> 2
this._options('a', 3) // устанавливает значение опций


Объявление public, protected, private методов


При помощи method(), publicMethod(), protectedMethod(), privateMethod() мы можем объявлять методы класса. Первым параметром указывается имя метода, вторым функция. method() может принимать третий параметр — уровень доступа, с возможными значениями: «public», «protected», «private» (по умолчанию используется «public»).
Как и в других объектных языках, приватные методы доступны только внутри методов класса. Защищенные, в том числе и внутри потомков класса. А публичные методы везде – как внутри, так и вне класса.

Создание экземпляра класса


Теперь создадим объект данного класса. Это можно выполнить несколькими способами.
// Создаем объект класса
var a = new A();
// -> Call constructor A::A() -> {a:1}

// другой способ создать объект класса A
var a = jsOOP.A.newObject({a:2});
// -> Call constructor A::A() -> {a:2}
Мы видим, что при создании объекта был вызван конструктор, где в качестве первого аргумента ему были переданы опции. Эти опции по умолчанию мы декларировали для данного класса выше при помощи функции options().

Вызов методов


В нашем примере метод fpub, вызывает метод fptc, а тот в свою очередь приватный метод fprv. Но напрямую вызов приватных и защищенных методов генерирует исключение.
a.fpub();
// -> Call public method A::fpub()
// -> Call protected method A::fptc()
// -> Call public method A::fprv()

a.fprv(); // -> throw "Call to private method jsOOP.A::fprv()"
a.fptc(); // -> throw "Call to protected method jsOOP.A::fptc()"
Данный механизм, в отличии от прочих реализаций ООП на Javascript, не создает методы внутри конструктора при инициализации каждого объекта, а описывает их один раз в prototype класса.

Атрибуты


Описанный в статье механизм не позволяет организовать уровни доступа для свойств (property) объектов класса. В данной реализации они названы атрибутами. Считаем, что все атрибуты объекта публичны.
// добавляем к классу A атрибут, с указанием значения по умолчанию
A.attribute('attr', 123)

//...
// объект класса
var a = new A();
a.log( a.attr ) // -> 123


Свойства


В рамках описанного механизма для поддержки уровня доступа свойств, было принято их организовать в виде методов. Свойства класса объявляются при помощи property(), publicProperty(), protectedProperty() и privateProperty()
// добавляем к классу A свойство prop
A.property('myprop', {
    get: function() {
        // возвращаем значение внутренней переменной
        return this._property('myprop')
    },
    set: function(value) {
        // устанавливаем значение внутренней переменной
        this._property('myprop', value)
    }
})
В отличии от объявления методов, для свойств можно указывать две функции: get и set, соответственно получения и установки значения свойства. По сути, внутренний механизм создает метод с названием свойства, вызов которого без параметров вызывает функцию get, с параметрами set.
this.myprop();        // возвращает значение
this.myprop(234);    // устанавливает значение

Если функция get или set в определении свойства опущена, она возвращает/изменяет значение внутренней переменной с названием свойства: this._property(название_свойства)

События


События, как и методы, могут иметь определенный уровень доступа. Добавляются они к классу при помощи функций event(), publicEvent(), protectedEvent(), privateEvent(), где в качестве первого аргумента передаем имя события.
// дополним класс А событием "myevent"
jsOOP.A
     .event('myevent')

Внутренний механизм добавляет к классу метод myevent(). Теперь для экземпляра класса мы можем подписаться на событие и сгенерировать событие.
var a = new A();

// подписываемся на событие
a.myevent(function(){
    this.log('Обработчик события myevent №1')
})

// подписываемся на событие
.myevent(function(){
    this.log('Обработчик события myevent №2')
})

// генерируем событие (запускаем обработчики событий)
.myevent()
// -> Обработчик события myevent №1
// -> Обработчик события myevent №2

Запуск myevent() с параметрами позволит передать их обработчикам событий в качестве аргументов. Бывает полезно, если нужно передать дополнительную информацию о возникающем событии.
Запуск myevent() с единственным параметром null удаляет всех обработчиков данного события.
Также возможно подписаться на событие сразу же при определении класса. Для этого в определении события event(), помимо названия события вторым аргументом нужно передать функцию обработчик.
// дополним класс А событием "myevent"
// и сразу же установим обработчик для всех объектов
jsOOP.A
.event('myevent', function(){
    // обработчик события
})


Наследование классов


Наследование класса осуществляется при помощи функции extend()
// объявляем класс B
jsOOP.createClass('B')
    
// наследуем класс A
.extend('A')

// определяем конструктор
.constructor(function(op){
    // вызов родительского конструктора
    this._call('parent.constructor', op);

    this.log('Call constructor B::B()')
})
Наследование, как и в некоторых объектных языках можно устроить с определенным уровнем доступа. При использовании privateExtend() все методы родительского класса, включая конструктор, становятся недоступны классу-потомку. protectedExtend() делает публичные методы родительского класса защищенными.

instanceof


Для проверки принадлежности объекта классу используем оператор instanceof
var b = new B();

b instanceof A // -> true
b instanceof B // -> true


Предопределенные методы


Для каждого объекта дополнительно создается несколько методов:
  • _property — приватный метод, для работы с какими либо внутренними переменными, доступ к которым возможен только внутри методов класса.
    // устанавливаем значение внутренней переменной (возвращает this)
    this._property('privateValue', value)
    // возвращает значение внутренней переменной
    this._property('privateValue')
    // возвращает значения всех переменных
    this._property()
  • _options — приватный метод; возвращает опции, указанные при инициализации объекта
  • _class — публичный метод; возвращает класс текущего объекта
  • _call — публичный метод; позволяет запускать методы, которые перекрыты классами-потомками


Множественное наследование


В определении класса ничто не мешает использовать extend() для нескольких родительских классов.
jsOOP.createClass('C')
    .extend('A')
    .extend('B')


Вызов родительских методов


В случае если класс потомок перекрывает методы родительского класса необходимо воспользоваться предопределенным методом _call.
В качестве первого аргумента функция принимает имя метода с указанием имени родительского класса через точку. Остальные аргументы передаются в качестве аргументов вызова функции.
this._call("A.fprv", arg1, arg2)
// тоже что и
this._call("jsOOP.A.fprv", arg1, arg2)
// тоже что и
this._call("classA.fprv", arg1, arg2)
Внутри класса можно в качестве имени класса использовать «self». Таким образом, мы будем точно уверены, что запустится функция именно текущего класса.
Поясню на примере:
//------ class A ------
jsOOP.createClass('A')
    .constructor(function(){
        // запускаем виртуальную функцию func()
        this.func();
        
        // запускаем именно A::func()
        this._call('self.func');
    })
    .method('func', function(){
        console.log('Call A::func()')
    })

//----- class B -------
jsOOP.createClass('B').extend('A')
    // перезапишем метод func()
    .method('func', function(){
        console.log('Call B::func()')
    })

var a = new A();
// -> Call A::func()
// -> Call A::func()

var b = new B();
// -> Call B::func()
// -> Call A::func()


Namespace


Каждый объявленный класс является, в том числе и пространством имен. Объявить класс в этом пространстве можно опять же несколькими способами:
// создаем класс D в пространстве имен A
jsOOP.A.createClass('D')
// или так
jsOOP.createClass('A.D')

// в том числе можно определить класс в еще несуществующем пространстве
jsOOP.createClass('newNamespace.E')
// newNamespace будет определено автоматически


Пример использования


Чтобы показать возможности библиотеки, хочу привести более приближенный к жизни пример.
В примере создается два класса: Component и его потомок Button.
(Дополнительно в коде используется фреймворк jQuery)

Класс Component
// объявляем класс Component
jsOOP.createClass('Component')
.options({
    width:    100,
    height:    100,
    text:    '',
    parent: document.body // jquery-selector or component
})
.constructor(function(op){
    this.createElement()
        .width(op.width)
        .height(op.height)
        .text(op.text)
        .afterRender()
})
.protectedMethod('createElement', function() {
    var par = this._options('parent');
    par = $(par instanceof Component? par._element() : par);
    this._property()._element = $('<div></div>').appendTo(par);
    return this
})
// функция возвращает созданный jquery элемент
.protectedMethod('_element', function(){
    return this._property('_element');
})
// добавляем событие
.protectedEvent('afterRender')

// добавляем некоторые свойства
.property('text', {
    get: function() {
        return this._element().text();
    },
    set: function(value) {
        this._element().text(value)
    }
})
.property('width', {
    get: function() {
        return this._element().width();
    },
    set: function(value) {
        this._element().width(value);
    }
})
.property('height', {
    get: function() {
        return this._element().height();
    },
    set: function(value) {
        this._element().height(value);
    }
})
;




Создадим для примера два экземпляра класса
// создаем компонент так
var com1 = new Component({text: 'First component'});

// или так
var com2 = jsOOP.Component.newObject().text('Second component').width(150).height(100);




Класс Button
// Теперь создаем класс Button в пространстве Component
jsOOP.Component.createClass('Button')

// и наследуем его от Component
.extend('jsOOP.Component')

// Переустановим некоторые параметры поумолчанию
.options({
    height: 30
})
.constructor(function(op){
    // Запускаем конструктор родительского класса
    this._call('parent.constructor', op);
})
// Добавляем событие click
.event('click')

// Добавляем обработчик на событие afterRender()
.protectedEvent('afterRender', function(){
    // при клике на элемент вызываем событие Button::click
    var self = this;
    this._element().click(function(e){
        self.click(e);
    })
})



Теперь можно создавать кнопки и назначать им обработчики событий
// указываем полный путь к классу
var button1 = new jsOOP.Component.Button({text: 'button-1'});

// или кратко
var button2 = new Button({parent:com2}); // (создадим кнопку внутри com2)

button2.text('button-2')
    // назначим обработчик по нажатию на кнопку
    .click(function(e){
        alert('click on button-2')
    })



Заключение


Надеюсь, статья получилась не слишком длинной и нудной. Я постарался описать кратко все возможности библиотеки.

Буду рад конструктивным замечаниям и предложениям.


+27
13400
92
denisskin 18,0

Комментарии (131)

+20
khizhaster, #
Ваше счастье, что мультипарадигменность Javascript-а со снисхождением смотрит на ваши детские шалости ;)
+2
dsCode, #
> со снисхождением смотрит на ваши детские шалости ;)

Да нет, шалости, как раз-таки, интересные. С точки зрения академического интереса воплощения одной из реализаций ООП (в данном случае, я полагаю, автор пытался приблизить JS к миру Java), постоянная проверка уровня доступа при каждом вызове одного метода — эффективней объявления тысячи методов.
+18
khizhaster, #
Да ничего интересно, вобщем то. Это очередная попытка притянуть за уши то, что не нужно. ЯваСкрипт «другой» язык и не нужно в него тянуть «привычные» вещи из других языков вместо того, что бы изучить именно язык.
В конце-концов, это всё тот же яваскрипт, и всё это сводится к {} объекту и prototype механизму. так не лучше ли использовать доступные простые механизмы для быстрой реализации чего угодно, чем тратить время на ненужные извраты, которые в итоге ничем толком не помогут?
0
dsCode, #
Ну то, что Вы сейчас написали, было написано уже тысячу раз (я, если что, тоже в курсе этого ;), и, по-моему, когда-то сам писал, что это никакая не имитация статично-классового ООП, а лишь обёртка, внутри которой — всё то же, prototype-based inheritnce). С другой стороны, если мы сейчас начнём сравнивать, к примеру Питон (а я всегда привожу его в пример в этом ключе ;)), то вряд ли Вы найдёте большие отличия от прототипной модели JS.
0
VlK, #
Ну-ка… Поведайте чуть-чуть о Питоне :) Даже интересно, куда там прототипы зарыли..!
+1
VlK, #
Ну… Это у вас что-то вроде принципиальной позиции?

В Питоне больше сущностей нежели в js, естественно, одна из которых — js. Это не делает именно Питон ближе js, это просто показывает гибкость динамических языков.

Как пример… Emacs Lisp. Старый язык, примитивное подмножество CLisp. Там нет даже замыканий! Однако, имея в наличии простейшие средства, программисты моделируют и более сложные фишки языка (модуль cl), и объектная система СLisp (eieio из комплекта cedet).

Но мы ж не ставим эти языки в один ряд!

0
VlK, #
Тьфу… Там «одна из которых (сущностей) — классы».
0
dsCode, #
> Ну… Это у вас что-то вроде принципиальной позиции?

Да нет, просто ECMAscript, действительно, питал некоторые идеи из Питона (можете проанализировать исходники, например, SpiderMonkey, там слово Python встречается ;)).

> В Питоне больше сущностей нежели в js

Ну, это уже другой вопрос. А в Руби — больше, чем в Питоне. Тем не менее, идеологически, они (JS, Ruby, Python) стоят в одном ряду.

> Это не делает именно Питон ближе js, это просто показывает гибкость динамических языков.

Ничего там никто не делает, они просто — стоят в одной линии в плане идеологии. При этом, во всех трёх — реализованы и свои идеи (в JS — это понятие «прототипа»).

> Но мы ж не ставим эти языки в один ряд!

Ваше право. А мы — ставим ;). Надо смотреть в суть. Поверхностных фич (которые я выше назвал — «свои идеи») может быть много и они могут варьировать; ядро же при этом, может быть одинаковое.
0
VlK, #
Ну какое ядро-то? Тот факт, что они динамические и все трое опираются на ООП в том или ином виде?

Простите, с Руби знаком крайне поверхностно, но про Питон знаю, что там есть четкий ряд metaclass->class->instance. Это целых три «измерения»! Про js знаю, что там этого ряда нет, а есть только отношение объектов как объект->объект(прототип).

Правила поиска атрибутов и методов разные, в Питоне гораздо больше скрытой механики, больше базовых средств и прочих сложностей…

И тот факт, что можно, извернувшись, смоделировать иерархию классов в javascript, еще не значит, что js — типа двоюродного брата. Не ближе троюродного точно :)
0
dsCode, #
> Ну какое ядро-то?

Самое главное. Истина же не страдает от того, понимает её кто-то или нет, верно?

> Тот факт, что они динамические и все трое опираются на ООП в том или ином виде?

Нет, это поверхностно. Факт, что в них: динамическое ООП со схожими разрешением свойств/методов и наследованием + свои примочки.

> Простите, с Руби знаком крайне поверхностно

Нет, Вы простите, что привожу, не уточнив. Ок, не будем про Руби, только Питон и JS.

> но про Питон знаю, что там есть четкий ряд metaclass->class->instance. Это целых три «измерения»! Про js знаю, что там этого ряда нет, а есть только отношение объектов как объект->объект(прототип)

Да ну это всё уже расширения, «ядро» (ответил выше) — схожее. Но, если хотите:

metaclass->class->instance:

metaclass === обёртка для создания коструктора;
class === конструктор + прототип
instance === порождаемый конструктором объект.

> Правила поиска атрибутов и методов разные

Как это? Покажите. Я показывал выше, что они схожие.

> в Питоне гораздо больше скрытой механики, больше базовых средств и прочих сложностей

Мелочи, расширение. Суть, ядро — остаётся схожим.

> И тот факт, что можно, извернувшись, смоделировать иерархию классов в javascript

Да какую ещё «иерархию классов»? Какое ещё «извернувшись»? Цепь прототип == иерархия классов в Питоне. «Зрите в корень»! (С)
0
VlK, #
Насчет метаклассов… Они позволяют много больше, чем просто завернуть конструктор в лишний декоратор, да чуть подправить правила наследования. Там еще широкие возможности изменения самого процесса определения класса.

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

В принципе, все эти надобъектные сущности питоновские можно, конечно, сообразить и на js. И наоборот. Но подгонка будет… Фрк. Извратом. Лишним грузом, просто-напросто. Хотя, конечно, экспериментировать и пробовать надо всегда.

Разные это языки, разные, писать надо по-разному. Ну привыкли все мыслить в понятиях классов и объектов, оттого и начинаем проецировать привычные категории в непривычную среду.

Хотя, конечно, Питон намного ближе js, чем, скажем, Haskell, естественно, или те же C++/java/C# просто в силу своей динамической природы.

Теперь личное. Мне глубоко симпатичен js за неординарность и внутреннюю простоту. :)) Слово неординарность — подчеркнуть :)
0
dsCode, #
> Там еще широкие возможности изменения самого процесса определения класса.

Спасибо, я Питон тоже знаю достаточно хорошо. Как и JS.

> В принципе, все эти надобъектные сущности питоновские можно, конечно, сообразить и на js. И наоборот. Но подгонка будет… Фрк. Извратом. Лишним грузом, просто-напросто. Хотя, конечно, экспериментировать и пробовать надо всегда.

Ну ладно, это Ваше мнение, я не буду на него посягать. Просто, при случае, если будет желание — покопайте оба языка глубже — увидите много схожего.

> Ну привыкли все мыслить в понятиях классов и объектов, оттого и начинаем проецировать привычные категории в непривычную среду.

Да нет, JS — это моя специализация. Если сказать не скромно (но честно) — я знаю его достаточно глубоко. Поэтому, «привыкли мыслить классами, пытаемся проецировать», извините, не про меня.

> Теперь личное. Мне глубоко симпатичен js за неординарность и внутреннюю простоту. :)) Слово неординарность — подчеркнуть :)

Ок, мне тоже ;)
+1
dsCode, #
Кстати, забыл дополнить (хоть и написал уже обобщённой фразой).

Вот эти выражения:

> очередная попытка притянуть за уши
> то, что не нужно
> ЯваСкрипт «другой» (ой, это самое слащаво-попсовое словосочетание ;))
> не нужно в него тянуть «привычные» вещи из других языков
> В конце-концов, это всё тот же яваскрипт
> не лучше ли использовать доступные простые механизмы
> тратить время на ненужные извраты, которые в итоге ничем толком не помогут

сегодня звучат слишком слащаво. Настолько слащаво, что их повторял каждый второй, кто более-менее разобрался в прототипах. Думаю, особо категорично так описывать нет смысла. Мы можем просто анализировать, сравнивать (с другими или схожими идеологиями, общей теорией), делать выводы и т.д.

Я знаю JS достаточно хорошо, но, почему-то когда в ответ на топики с обёртками начинают писать подряд эти слащавые фразы (где так же — все подряд слащаво плюсуют ;)) — толку от
этого столь же мало, как и говорить «полноценное ООП на классах в JS». Ну ладно раньше, надо было жёстко клином выбивать дурь из начитавшихся только о Prototype.js и jQuerty, ну сейчас-то — все, вроде, грамотней стали — зачем та же стилистика ответов?
+20
chiaroscuro, #
Покажите пример использования. Где, когда и в каких ситуациях в JS нужно такое ООП?

Там же прототипное бесклассовое ООП, коммунизм и все такое…
–1
denisskin, #
Там же и в тех же ситуациях, когда требуется ООП в принципе. Инкапсуляция, полиморфизм и прочее.
0
deerua, #
Парадигмы ООП вы знаете, а вот всё же пример увидеть было бы неплохо ;)
Понимаете, «такое» ООП — оно скорее для бизнес-логики под конкретный проект, в джс это не нужно, излишне…
+1
denisskin, #
Полностью поддерживаю. В целом для js это ненужно.
Подобный механизм реализован скорее для единообразия в написании кода:
Есть класс. Его можно поместить в отдельный неймспейс. Методы его можно объявить отдельно. задать им уровень доступа. Тут же оставлять комментарий с описанием функционала и списком параметров, из которых потом автоматически генерируется документация. По принципу:
/*
* Описание метода
* @access protected
* @param int a
* @param int b
* @return bool
*/
.protectedMethod('method', function(a, b){
})

А обычно это происходит как угодно:
можем дополнить прототип методами: class.prototype.method=function(){},
можем дописать методы к объекту this.method = function(){} в конструкторе или еще где-нибудь. С приватными методом еще хуже, их описывают внутри функций, чтоб небыло доступа извне.
В результате нет единообразия.
+3
deerua, #
А на живых прожектах есть применение?
зы: я наверное потому люблю джс, что он поддерживает парадигму «кручуверчу» (с) korj
+2
qmax, #
я бы сформулировал по другому:
«покажите пример, где такое ООП даёт очевидные приемущества по сравнению с использованием нативного подхода.»
+3
slik, #
> К сожалению, в своей практике освоения Javascript мне не приходилось встречать толковой реализации классов и механизмов наследования.

В сторону MooTools не смотретли?
–5
barbuza, #
судя по этому трехколесному средству передвижения — нет
+3
dsCode, #
> судя по этому трехколесному средству передвижения

А почему такая пренебрежительная оценка? У Вас есть наработки лучше? Какие-то другие обёртки считаете лучше? Почему?
–4
barbuza, #
а вам что, это понравилось? в сравнении с обертками для классов, которые предоставляет mootools — это полный бред.
+1
dsCode, #
> в сравнении с обертками для классов, которые предоставляет mootools — это полный бред.

Обоснуйте. В каких моментах?
–5
barbuza, #
я не вижу что здесь можно сравнивать. сравните мне помидор с emacs например.
+7
NickMitin, #
0
nIx0iD, #
отличный пример кстати :)
–2
dsCode, #
> я не вижу что здесь можно сравнивать

ну так, а если не видите, зачем тогда болтать о каких-то «трёхколёсных велосипедах»?
0
barbuza, #
картинка выше очень точно отражает то, как можно сравнить mootools и «jsOOP»
–1
dsCode, #
> картинка выше очень точно отражает

А Вы заглядывали в реализацию mootools? Ну вот, если честно, положив руку на сердце? ;)
0
barbuza, #
по долгу службы смотрю внутрь мутулза почти каждый день.
0
VlK, #
Ага, пришел мудрейший, пробормотал «говно»; и слился.
0
dsCode, #
Ага, жаль, что из-за таких «мудрейших» (когда их количество начинает зашкаливать на квадратный метр топика ;)), весь Хабр — может походить на сборище возомнивших о себе нубов, которые считают своим долгом ляпнуть (с деловым видом, конечно ;)) какой-нибудь бред (при этом очень поверхностно или вообще не разбираясь в предмете). И после аргументированных ответов им ничего не остаётся, как жать минус. Я призываю всех не уподобиться трусливым невеждам.
0
chiaroscuro, #
В Qooxdoo есть стоящая объектная модель. Она таки лучше, ибо магического кода писать надо меньше.
–1
dsCode, #
А, ну Вы с точки зрения использования. Не знаю, возможно. Я больше подразумевал внутреннюю реализацию. Вообще, обёрток куча, но, все они, на одно лицо, поскольку, внутри них — всё то же, единственное в JS, prototype based inheritance. Поэтому, обёртка — является лишь обёрткой — удобным блоком для code reuse'a, но не более.
0
chiaroscuro, #
Там не просто обертка, а нечто более хитрое. Ну и реалии другие совсем: это GUI-фреймворк, который ближе к десктопным, нежели к Dojo/YUI/etc.

Разумеется, это не значит, что объекты важнее их взаимодействия. Упор чаще делают на первое, когда лучше бы — на второе. Я немного пытаюсь реализовать то, о чем тут говорю, но это к теме уже не относится. :)
–1
dsCode, #
> Там не просто обертка, а нечто более хитрое

В каком плане? Там есть что-то сверху Javascript'a (в смысле, какой-то другой языка программирования, который парсит псевдо-js-код)? Если это обычная библиотека на Javascript'e, то там обёртка.
0
chiaroscuro, #
> В каком плане? Там есть что-то сверху Javascript'a (в смысле, какой-то другой языка программирования, который парсит псевдо-js-код)?

en.wikipedia.org/wiki/Qooxdoo#Object-oriented_programming
qooxdoo.org/documentation/0.8/oo_introduction
qooxdoo.org/documentation/0.8/oo_feature_summary

Небольшой DSEL + кодогенерация, благо в JS это немного проще, чем в Java. :)

> Если это обычная библиотека на Javascript'e, то там обёртка.

Наверное, я не понимаю значение термина «обертка».
–1
dsCode, #
Скачал, посмотрел. Обычная обёртка, не более. См. Class.js, метод __createClass (строка 945 в текущей версии). Самая обычная связка прототипов (cм. начиная со строки 1020):

.from Qooxdoo framework -> Class.js
var helper = this.__createEmptyFunction();
helper.prototype = superproto;
var proto = new helper;

// Apply prototype to new helper instance
clazz.prototype = proto;

// Store names in prototype
proto.name = proto.classname = name;
proto.basename = basename;


> Наверное, я не понимаю значение термина «обертка».

Значение — самое прямое. Это лишь обёртка, внутри которой — единственное в JS — prototype based inheritance (которое схоже, например с динамическим классовым из Питона). Суть этой обёртки (я снова повторяюсь, но — с благой целью — закрепить материал ;)) — обеспечить удобное повторное использование кода.
0
dsCode, #
Ну и в чём опять дело? Ну я понимаю, возразить нечего, но зачем минус-то жать? Ой, Хабра-хабра… xD Выйди, покажись, кто минусует? Если, конечно, ты действительно знаешь JS ;) Мы будем пообщаться достойно и аргументированно (если у тебя есть смелость на это и знания;)), но, пожалуйста, не гадь здесь, а?
0
barbuza, #
минус жмут когда несогласны — вполне логично
если хочешь поспорить аргументированно — отдельной веткой каментов пиши преимущества данной библиотеки над другими, а я попробую доказать свое первое утверждение (про велосипед).
0
dsCode, #
> минус жмут когда несогласны — вполне логично

Да нет, человек, Вы минус за зря жмёте (и логика сбитая, ага ;)), не разбираясь, знает человек о чём говорит или нет. Это признак слабости (в области знаний предмета имеется в виду).

> если хочешь поспорить аргументированно — отдельной веткой каментов пиши преимущества данной библиотеки над другими, а я попробую доказать свое первое утверждение (про велосипед).

Я уже отмечал. Типичное классическое поведение испугавшегося, что ему придётся что-то аргументированно подкреплять после ляпнутой фразы. Почему-то, в данном случае, такой субъект считает, что ему должны кто-то что-то доказывать (ну да, естественная психологическая попытка взять ситуацию в свои руки, в ведущую позицию). Этот дешёвый трюк меня всегда это умиляет, спасибо ;)

Ну, естественно, нет ;) Это Вы мне сейчас предоставите все факты, подкрепляя теорией и практикой (кодом), свою деловую фразу о «трёхколёсных велосипедах» а я — докажу Вам обратное (я подчёркиваю — докажу, а не попробую доказать).

Кстати, есть другой путь — Вы спрашиваете, что не понятно в JS (и, как следствие — во всех одинаковых обёртках — хоть mootools, хоть prototype.js), а я Вам рассказываю.
0
barbuza, #
хорошо, скажи мне, в jsOOP вызов функции, переданной в качестве метода обернут в еще одну функцию с проверками? если да — то этого уже достаточно чтобы код, написанный с использованием этой библиотеки был существенно медленнее чистого js.
0
dsCode, #
Ага, попытка хоть как-то реабилитироваться после полнейшего фэйла (и поставленных за зря минусов ;)). А то ты сам не видишь, что там куча обёрток сверху? А то, я сам это не отмечал (дважды, причём)? Демагогия, чтобы отвести внимание. Я наоборот это описывал, как особенность этой обёртки (что проверки при каждом чихе — тоже внесут расходы, но будут лучше, чем описывать 100 функций в конструкторе), а ты, опять, с деловым видом пытаешься спрашивать то, что выдаётся открыто, без вопросов и скрытностей.

> если да — то этого уже достаточно чтобы код, написанный с использованием этой библиотеки был существенно медленнее чистого js.

О-о-о ;) Ну здесь вообще 5 баллов. Чистого JS. Браво! Профессиональный этический соскок в нужное мэйнстримовое русло =) Ты про мутулз рассказывай, с которого начал, нечего сливаться с темы. И конкретно (я повторю и настаиваю) про «трёхколёсные велосипеды».
0
barbuza, #
в мутулз вызовы не обернуты. и хватит ныть про минусы, вроде не первый день на хабре.
0
dsCode, #
> в мутулз вызовы не обернуты

Как и ещё в тысячи подобных обёрток — из кучи фреймворков ;) молодец, возьми пряник с полки. Речь не об этом, речь о том, что ты с деловым видом кидаешься фразами, приводя аргументами ещё большее кидание пустыми фразами, и в виду полного фэйла, скатываешься до бреда (ну и, как следствие, начинаешь жать минус тем, кто прав ;)).

> и хватит ныть про минусы, вроде не первый день на хабре.

Демагогия, фальш.

Либо признавай, либо засчитываю за слив и — свободен.
0
barbuza, #
вот тут ты уже показываешь полное незнание предмета. методы в мутулзе обернуты в аналогичную проверку, ты хорошо ведешься на провокацию. предлагаю дальше не спорить, потому что это вызывает у тебя слишком бурную реакцию, мало относящуюся к предмету спора.
0
dsCode, #
> вот тут ты уже показываешь полное незнание предмета

Спасибо, «оценил».

> ты хорошо ведешься на провокацию

Да ну, брось, она настолько не прикрыта, что тут и вестись-то нечего, я просто открыто, не парясьи никому не поддакивая с тобой беседую. Если кому-то кажется агрессивно, как результат поддачи на провокацию — меня это мало волнует ;)

> предлагаю дальше не спорить

Твоё право. Ок.

Цитирую себя же:

>> либо засчитываю за слив и — свободен

Засчитываю.
–1
can3p, #
какой забавный троль, этот dsCode, Гомера Симпсона напоминает.

«Лалала, ничего не слышу!»
0
DenVdmj, #
«что проверки при каждом чихе — тоже внесут расходы, но будут лучше, чем описывать 100 функций в конструкторе»
А Вы действительно думаете что функции будут _фактически_ созданы при каждом вызове конструктора?
Я вот, тоже, не люблю такой подход когда в куча финкций создается, но мне думется что последние экма-движки не должны этого делать.
Касательно того как это может выглядеть «под капотом» — функция есть объект с оператором вызова (), ссылкой на тот экземпляр лексического контекста в котором она создана, и собственно указателем на сам код функции. Оператор при вызве передает телу функции ссылку на контекст также как обычно передается this. То есть создание функций-клонов будет очень дешевым, и по скорости и по памяти.
Кто-нибудь пробовал делать тесты в разных движках, чтобы оценить потери в памяти?
0
dsCode, #
> А Вы действительно думаете что функции будут _фактически_ созданы при каждом вызове конструктора?

Вообще, спецификация определяет два механизма по оптимизации, связанные с функциями (затрагивал этот момент в одной из статей): это тождественные правила грамматики (13.1.1) и объединённые объекты (13.1.2). Если внутреннее свойство [[Scope]] не различимо для двух и более функций, реализация вправе использовать один объект. Например:

function a() {
   function b(x) {
     return x* x;
   } 
   return b; 
}

var x = a();
var y = a();

Здесь реализации могут объединить объекты x и y, и, более того, использовать один объект.

Однако, например, функции, порождённые конструктором Function — никогда не объединяются, т.е. даже в цикле (из 100 итераций) в глобальном коде, где у всех функций был бы один [[Scope]], всё равно будет создано 100 функций (в случае же декларации функции или функции-выражения, могут быть созданы объединённые объекты).

> но мне думется что последние экма-движки не должны этого делать

Ну а что гадать. Стандарт чётко описывает предложение по оптимизации в данном случае, однако, реализацию данного предложения — оставляет, естественно, движкам (т.е., теоретически, движки могут и не воспользоваться этим предложением, практически же — думаю все современные движки данную оптимизацию с объединёнными объектами делают).

> Оператор при вызве передает телу функции ссылку на контекст также как обычно передается this

Лексический контекст хранится внутренним свойством [[Scope]] и никуда никому не передаётся, он зашит в функцию при её создании — раз и навсегда до уничтожения функции.
0
DenVdmj, #
О, спасибо за развернутый ответ ))
quote: «Лексический контекст хранится внутренним свойством [[Scope]] и никуда никому не передаётся»
Мне не с руки использовать экма-терминологию, но речь шла за то что не имеет смысла клонировать одинаковые функции-замыкания, поскольку единственное чем они отличаются — это разные экземпляры «родительских» scope. И если на уровне реализации иметь «развязку» между собственно функцией и тем scope в котором она рождена, то проблем с дублированием одинакового кода не будет. Это безотносительно экма-стандартов, но раз там все так хорошо расписано, то можно только порадоваться за разработчиков движков ))
–1
chiaroscuro, #
Мы о разных вещах говорим. :) Я говорю об объектной системе, а Вы — о реализации динамической диспетчеризации в ней.
0
dsCode, #
> Мы о разных вещах говорим

Ну, тогда могу лишь посоветовать изучать Javascript глубже :)
–1
chiaroscuro, #
Что именно? Детали реализации интерпретатора? Увольте.
0
dsCode, #
> Что именно? Детали реализации интерпретатора?

Можете и конкретные реализации покопать (если интересно), но вообще, я имею в виду, безотносительно реализаций, стандарт ECMA-262.

> Увольте.

Как скажете. Увольняю.

0
dicos, #
Хотелось бы знать мнение о ExtJs: сколько у него колес и что это за средство передвижения?
0
denisskin, #
MooTools поддерживает protected методы?
+1
slik, #
Вообще, это зависит от стиля написания кода. Вообще, приватные методы в яваскрипте — это не что иное, как создание функции внутри другой функции. Изходя из этого и надо писать.
+1
denisskin, #
Я как раз в начале и написал, что создание приватного метода внутри другой функции не совсем удобно. По моему, удобнее отдельно определить в классе приватный метод.
0
VlK, #
Почему? Вполне адекватно. Есть как бы верхний слой функций плюс набор предельно мелких локальных функций в методах, где это требуется.
0
slik, #
var Button = new Class({
implements: [Options, Events, jsOOP.Component],
options: {
height: 30
},
initialize: function(op) {
this.setOptions(op);
}
});

var btn = new Button(/*{options}*/);
btn.addEvent('click', function() { alert('ola'); });

Что-то типа того…
0
denisskin, #
Согласен. Очень похоже. Наверное, единственное исключение от MooTools в уровне доступа к методам.
+10
superhabra, #
О боже, зачем насиловать javascript?
+1
superhabra, #
Кстати, с таким названием уже есть подобная библиотека: habrahabr.ru/blogs/webdev/46414/

И вообще, чтобы не создавать таких костылей надо выучить джаваскрипт и понять что это не чистый ОО язык, а скорее прототип-ориентированный.
0
denisskin, #
> Кстати, с таким названием уже есть подобная библиотека

Не знал. Посмотрю
0
dsCode, #
> надо выучить джаваскрипт и понять что это не чистый ОО язык

Вот, действительно, надо выучить Javascript, чтобы глупостей не писать. JS — объектно ориентированный язык.
0
superhabra, #
JS, вообще-то, мультипарадигмальный язык прграммирования.
0
dsCode, #
Я в курсе, спасибо. И основная из его парадигм — объектно-ориентированная.
+1
znvPredatoR, #
Интересно, а как понять что именно она основная?) По-моему в нём также достаточно вещей которые свойственны функциональным языкам.
0
dsCode, #
> Интересно, а как понять что именно она основная?) По-моему в нём также достаточно вещей которые свойственны функциональным языкам.

Действительно ;) JS поддерживает и функциональную стилистику. Чтобы найти чёткую грань, нужно проанализировать ключевые особенности и концепции чисто функциональных языков.

Можно кстати, обратиться к ECMA-262-3, где заявлено (в overview, параграф 4):
ECMAscript is an object-oriented programming language for performing computations and manipulating
computational objects
0
dsCode, #
> JS, вообще-то, мультипарадигмальный

Кстати, если под «не чистый ОО язык» Вы имели в виду мульипарадигменность, то за «глупости» я прошу меня извинить (поскольку, мне показалось, Вы говорите в ключе «не чистый ОО язык» — «т.к. в нём нет классов, private/protected/public и прочей лабудыпрочих сущностей из других реализаций ООП»). Однако, Вы, всё же, сказали «а скорее прототип-ориентированный.», что подразумевало, что Вы имеете в виду больше не мультипарадигменность, а, всё-таки, связь с «классами, private/protected/public и т.д.», поэтому, всё остаётся в силе, но, надеюсь, Вы не воспримите это агрессивно, а наоборот — как передачу Вам информации.
–3
dsCode, #
> О боже, зачем насиловать javascript?

прям-таки, насиловать? ;)
–1
dsCode, #
Блин, какая фигня минусует за зря? Выйди, покажись, дружище ;) Мне есть что сказать, рассказать о JS. Уверен, что тебе тоже?
+4
djko, #
Javascript — уникальный язык, потому как прототип-ориентированный и весьма популярный. Так ли уж необходимы protected методы?
+2
denisskin, #
Согласен. В данной реализации был скорее спортивный интерес.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
+2
denisskin, #
Да, тоже об этом думал. Доделаю
НЛО прилетело и опубликовало эту надпись здесь
+1
dsCode, #
Не волнуйтесь, минусуют всегда лузеры, не способные вести достойную дискуссию.
+4
Kaluchi, #
Меня огорчает то, что некоторые программисты называют javascript не-ООП языком.
Поймите же наконец: ООП != [инкапсуляция + наследование + полиморфизм]. Если не верите — изучите этимологию этих слов.

Когда вы разделите эти понятия, думать и программировать станет намного проще.
+2
johndow, #
Тоже удивляет меня почему люди с упорством достойным лучшего применения пытаются загнать JS в рамки [инкапсуляция + наследование + полиморфизм] и называют эти рамки полноценным ООП.
+2
chiaroscuro, #
> Когда вы разделите эти понятия, думать и программировать станет намного проще.

Судя по мейнстриму загонять себя в рамки, а потом преодолевать их, не изменяя (шаблоны, привет) — это целая индустрия. :)
0
Kaluchi, #
Умение загонять людей в «религиозные» рамки — это хитрая наука.
0
aubt, #
мыши плакали, кололись, но продолжали есть кактус ©
–2
Kaluchi, #
Не поверите, жава — далеко не самый колючий кактус среди языков программирования :)
0
aubt, #
причем тут Java?
и я не про язык вообще.
0
Kaluchi, #
А ёлы палы)) Я с другим топиком перепутал про жаву)) Извините
0
mas, #
Хорошая книжка для знающих js — oreilly.com/catalog/9780596517748/ Там и про разные объектные подходы, и про то, как надо и не надо делать, и про многое другое. Рекомендую.

И тот же вывод — не надо насиловать js и делать из него то, чем он не является.
–1
dsCode, #
> И тот же вывод — не надо насиловать js и делать из него то, чем он не является.

В смысле?

0
dsCode, #
> чем он не является

А чем он не является? И чем является?
+4
dsCode, #
Своеобразная обёртка, интересная. Естественно, создание одного «сахара», влечёт за собой дополнительные расходы в другом месте (постоянные проверки private/protected/public при каждом чихевызове метода), но в целом, желание и реализация, достойны оценки и, в плане расходования ресурсов, уж явно лучше объявления n-ого количества одинаковых методов для создания «приватных» свойств.

Однако, я думаю, у Вас всё же больше был интерес академический, хотя, если Вы применяете (и Вам удобно применять) эту обёртку в real-life проектах, это тоже хорошо.

> this._call('parent.constructor', op);

Можно было ещё реализовать фишку с this._super(), чтобы не заморачиваться каждый раз с именем parent-метода, где _super в каждом одноимённом методе будет указывать на такой же метод из parent-класса.

Ну, и плюс несколько терминологических «придирок» (на самом деле, уточнений ;), чтобы быть в курсе в следующий раз).

> Полноценное ООП в Javascript

В JS — изначально заложено полноценное ООП. Всегда привожу пример: alert(1..toString); Эта одна строка показывает и объектную сущность и наследование, которым JS пропитан насквозь.

> с определенным уровнем доступа (public, private, protected) и дарит прочие вкусности объектно-ориентированного программирования

В общем, public, private, protected — синтаксический сахар некоторых реализаций ООП. Является исключительно удобным синтаксическим сахаром и усилением абстракции, но не основой ООП. Главное, осознавать, что инкапсуляция в большей мере — это абстракция, а не параноидальное сокрытие. Существует для удобства программистов, а не как защита от «злого хакера». Как вариант, можно посмотреть реализацию уровней доступа в Питоне — соглашение об именовании: _protectedProperty (одно ведущее подчёркивание), __privateProperty (два подчёркивания), publicProperty. С одной стороны __privateProperty будет доступно внутри класса, но с другой стороны, Питон просто переименовывает такие свойства в _ИмяКласса__privateProperty, которые становятся доступны снаружи. Тем самым не перегружается код (и на уровне реализации) в плане всевозможных проверок, и инкапсуляция, как помощник программисту, и усилитель абстракции, имеет место быть.
0
shergin, #
Полностью согласен.
При реализации собственного js-oop фреймворка я как раз первым делом пытался решить проблему с красивым вызовом базового метода this.base(a, b, c) и красивым получением ссылки на «родительский класс» this.super().method(a, b, c), так чтобы функции оттуда по умолчанию вызывались в контексте текущего объекта. Второе мне сделать пока не удалось (сделать эффективно, без создания кучи функций-оберток), поэтому пока приходится писать примерно так: this.super().method.call(this, a, b, c).
Я принципиально не хочу передавать имена функций как строковый параметр.
0
denisskin, #
Боюсь, строкового параметра полностью не избежать, поскольку иногда нужно вызвать методы конкретного родительского класса (если таковых много). Вообще, в данной реализации _call вызывает метод, который можно вызвать напрямую. В каждом объекте сохраняется методы родительских классов. (правда, в названии присутствует точка).
this['jsOOP.BaseClass.method'](a, b, c)
Функцией _call, просто, можно опускать полное название класса.
this._call('parent.method', a, b, c).

Вообще, есть возможность доработать механизм, чтобы перекрытые методы базовых классов вызывались как-нибудь так: this._super_method(a, b, c). Но в данном случае получается не универсально: поскольку методы могут неоднократно перекрываться.
0
dsCode, #
> Но в данном случае получается не универсально: поскольку методы могут неоднократно перекрываться.

Как вариант, просто this._super() будет вызывать одноимённый метод из непосредственного предка, this._super(Предок) — из конкретного предка.
+4
proxor, #
Почему каждый считает своим долгом добавить в JS «полноценную» поддержку ООП, и ни разу не задумывается о том, что она там уже есть. И более полноценная чем где-либо. Прототип-ориентированный вариант ООП в JS лично мне куда ближе и приятнее, чем традиционный в других ОО-языках. Переступите наконец через свою косность и въевшиеся привычки и потратьте пару часов на освоение ООП в JS. Оно вам обязательно понравится ;)
–3
shergin, #
Признайтесь, у вас просто не было задач, для решения которых прототипная ООП-модель неэффективна.
0
znvPredatoR, #
Боюсь процент этих задач столь мал, что их у большинства не было. Вот я работаю с js 2 года, а таких не встречал. Можете привести примеры?
0
Zitrix, #
«не встречал» или «не искал»?
это от стиля решения задач зависит: как только доходит до «private» переменных (которые var x, а не this._x), прототип сходу не помогает.
0
dsCode, #
> прототипная ООП-модель неэффективна

Так в том-то и дело, что она мало чем отличается от «динамической классовой» ;)
0
dsCode, #
> чем традиционный в других ОО-языках

Не устану повторять: «класс vs. прототип» — не столь существенно. Более (и кардинально) существенно «статика vs. динамика». Как вариант, тот же Питон. Или Руби. У них очень похожие с JS модели наследования и расширения, но тем не менее, в них присутствует понятие «класс» — как «синтаксический сахар», который достигается в JS — путём обёртки. Суть обёртки — удобный code reuse.
–8
deniamnet, #
когда мне надо сделать что-то современное на js, то я беру любой фреймворк — jQuery, mooTools или prototype… я сильно сомневаюсь, что Вы умнее в js, чем John Resig или Valerio Proietti — эти люди обглодали js до костей и кроме этого им помогали другие разработчики
на мой взгляд, бесполезно делать на js то, чего в нем просто не существует (я про полноценный ООП)

0
gentleman, #
Ладно в mootools есть реализация оберток для классов, но при чем здесь jquery, касательно топика?
0
dsCode, #
> я сильно сомневаюсь, что Вы умнее в js, чем John Resig или Valerio Proietti

«Оставь сомнения, всяк читавший ECMA». ;| шутка )) а, если серьёзно:

> на мой взгляд, бесполезно делать на js то, чего в нем просто не существует (я про полноценный ООП)

— не «болтайте ерундой»
0
Zitrix, #
нюню, а делать из JS средство для работы с DOM'ом — надо (я про то, как разрабы фреймворки юзают)?
0
nuit, #
вам сюда Universal Design Pattern
+4
wally, #
Полноценное ООП в Javascript?
В Javascript и так полноценное ООП. Ваша библиотека — это скорее обертка, для удобства программирования, тем программистам, кто долго работал, к примеру, с Java или C#.
И то, что в JS нет магических слов: class, private или protected, не делает язык не объектно-ориентированным. Javascript — полноценно объектно-ориентированный язык программирования.
Просто это объектно-ориентированный язык, основанный на прототипах.
+1
denisskin, #
> Ваша библиотека — это скорее обертка, для удобства программирования
Да — всё это именно для удобства.
Повторюсь: Подобный механизм реализован скорее для единообразия в написании кода:
Класс можно поместить в отдельный неймспейс, методы можно объявить отдельно, задать им уровень доступа, тут же оставлять комментарий с описанием функционала и списком параметров, из которых потом автоматически генерируется документация. По принципу:
/*
* Описание метода
* @access protected
* @param int a
* @param int b
* @return bool
*/
.protectedMethod('method', function(a, b){
})
А обычно это происходит как угодно:
можем дополнить прототип методами: class.prototype.method=function(){},
можем дописать методы к объекту this.method = function(){} в конструкторе или еще где-нибудь. С приватными методом еще хуже, их описывают внутри функций, чтоб небыло доступа извне.
В результате нет единообразия.
+2
denisskin, #
Что касается полноценного ООП в Javascript. Очень сильно жалею, что позволил себе применить слово «Полноценное». Я вполне считаю js языком с полноценным ооп. Более того считаю его языком с высокими возможностями, поскольку не имея в распоряжении магических слов class, private и прочих, можно реализовывать все эти вещи в нем. Собственно говоря, поэтому я пишу эту статью.
0
Kaluchi, #
Приятно было увидеть этот комментарий. Думаю, что топик «Полноценное ООП в Javascript» стоит переименовать в «Полноценные классы в Javascript»
0
dsCode, #
> «Полноценное ООП в Javascript» стоит переименовать в «Полноценные классы в Javascript»

Если более точно, то будет чуть длиннее: «Определение сущностей в JS-ООП из других реализаций ООП» ;)
0
denisskin, #
Переименовал топик )
0
Snipe, #
Хватит издеваться над языком =)
Он самый что ни на есть объектно-ориентированный, там кроме объектов считай и нет ничего!
0
piumosso, #
Даже функции — и то объекты)))
0
dsCode, #
> Хватит издеваться над языком =)

Хватит повторять за всеми =) А, если я попрошу объяснить, что такое «издеваться над языком», сможете?

> Он самый что ни на есть объектно-ориентированный

Ага ;)

> там кроме объектов считай и нет ничего!

Есть ;) Ещё и примитивы.
0
dsCode, #
Я попрошу минсующих нубов удержаться от минсов за зря. Я говорю истинно. Если есть что возразить, рассказать, показать — пожалуйста — я с удовольствием пообщаюсь, но зачем просто так жать минус? ;)
0
Snipe, #
> Хватит повторять за всеми =) А, если я попрошу объяснить, что такое «издеваться над языком», сможете?

Да я не повторял, если честно. Зашел и написал — потом полез читать другие комментарии.
Просто так заходишь: «О, статья про Javascript», — а тут в очередной раз рассказывают как классы сделать. =\
Причем сделать их можно многими многими способами, т.е. и статей может получиться оченно много.

Я наверное не там работаю, но никогда не встречал таких задач, где бы действительно нужны были все эти навороты.

> Есть ;) Ещё и примитивы.
Ну ессно, куда без них. Слово «считай» не случайно. ;)
+1
piumosso, #
По мне, так немножко сложновато…
А вы тестировали на производительность?
0
Rhaps107, #
> К сожалению, в своей практике освоения Javascript мне не приходилось встречать толковой реализации классов и механизмов наследования

Эээ. Как бы в JS-фреймворках это уже сделано
PrototypeJS: www.prototypejs.org/learn/class-inheritance

Или я что-то путаю?
+1
dsCode, #
> Или я что-то путаю?

Да нет, не путаете. Обёрток куча. У автора топика — очередная, но своеобразная.
0
k0rzhik, #
Интересно, полезно в качестве разминки для мозга, но не нужно. ИМХО.

Могу предложить такой вариант…

var myclass = (function(){
	
	// private var
	var myPetName;
	
	// private method
	function log(msg){
		console.log(msg)
	}
	
	// constructor
	var constructor = function(){}
	
	// public props & methods
	constructor.prototype = {
		name: '',
		getName: function(){alert(this.name);},
		setName: function(name){this.name = name;},
		getPet: function(){alert(myPetName)},
		setPet: function(n){ myPetName = n}
	}
	
	return constructor;
	
})();

a = new myclass();

a.setName('Korzhik');
a.getName();

a.setPet('Belka');
a.getPet();
0
yroman, #
А в вашем варианте переменная myPetName разве не будет шариться между всеми экземплярами myclass?
0
dsCode, #
Будет, видно же.
0
yroman, #
ну это тогда какая-то неправильная приватная переменная =) Какая-то статическая вообще, не канает.
0
dsCode, #
Ага.
0
k0rzhik, #
Ага, будет. Виноват, что-то протупил перед сном)
Да и парсер съел почему-то вторую часть — про внесение приватных методов и свойств в конструктор, а публичных — в прототип
0
mocksoul, #
violates «kiss».

а если серьёзно — не нужно это в яваскрипте, имхо, совсем.
0
TEHEK, #
Взял на заметку полезную махинацию:
cls.extend = function(methodsAndProperties, access){
var exAccess = {
'public': {'public':'public', 'protected':'protected','private':'private'},
'protected':{'public':'protected', 'protected':'protected','private':'private'},
'private': {'public':'private', 'protected':'private', 'private':'private'}
}[access||'public']||{};
...


Однако ж… По большому счету у вашей вещи чисто спортивное применение. Ну я НИКАК не могу понять, зачем так наворачивать, когда в любой момент кто угодно может сделать

// ... ваш пример компонента

com1 = new Component();

// создаем гейтвей, который работает даже для уже инициализированных объектов
Component.method('expose', function (method, arg1, arg2, arg3) {
return this[method](arg1, arg2, arg3);
})

// вуаля
com1.expose('_element', 12,3,4);



К тому же, даже к свойствам класса надо обращаться со скобками. Я вот только сегодня видел тут такое извращение ради того, чтобы скобки не писать

=)
0
mihalicyn, #
Странно, что столько слов и не заметили самого главного,
сразу после прочтения кода этой «поделки», я понял, что существует случай, когда
она сработает некорректно — асинхронный режим:
// объявляем класс A
jsOOP.createClass('A')

// объявляем конструктор
.constructor(function() {})

// определяем публичный метод log()
.method('log', function(s){
//вызываем приватный метод
setTimeout(this.fprv, 100);
//хе-хе, метод log-то выполнение закончил, из стека он удалится — получим ошибку!
//не верите? Запускайте!
})

// добавляем приватный метод fprv()
.privateMethod('fprv', function(){
alert('Private method A::fprv() called!')
})

var a = new A();
a.log();

Но додуматься до такого алгоритма реализации — дорогого стоит, автор молодец, пусть даже механизм и не всегда правильно срабатывает.

Я надеюсь, все понимают, что это не фиксится… -)

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