Раз за разом я читаю, что удобные библиотеки для создания классов на Javascript, видите ли, не соответствуют идеологии языка и тем, кто их использует просто необходимо учить язык. Такое говорят невежды, которые и сами толком не разобрались ни в самом языке ни в библиотеках, которые они критикуют. И так часто говорят, что я решил написать этот топик и просто давать ссылку
Обёртки в нормальных библиотеках совершенно не противоречат идеологии Javascript и прототипно-ориентированного программирования. Они просто предоставляют удобный интерфейс, алиас для его использования. Конечно, есть библиотеки, которые реализуют «ООП в Javascript» через какие-то черезжопные методы, но сейчас такие во внимание не берем, а рассматриваем их на примере Мутулз.
Например, для конструкции
Введен алиас, который позволяет не повторять
Следующая конструкция для наследования (заметьте, она полностью соотсветствует идеологии Javascript и «ловится» с помощью
Инкапсулируется в такую простую запись:
И еще много-много-много. Суть в том, что оно не нарушает идеологию JavaScript. Оно под неё подстраивается и предоставляет удобный интерфейс, а внутри это всё то же самое, что делали бы профессиональные. Ведь идеология прототипно-ориентированного программирования — это не многословность и постоянные упоминания слова «prototype», а невероятная расширяемость.
А идеологию нарушает как раз другой, очень вредный и очень популярный подход — перегруженный конструктор:
Который нельзя наследовать так, чтобы работал
Я уж молчу про то, что будет в Internet Explorer. Сами проверьте. Можно оставить компьютер включённым на ночь =)
Даже то, что он позволяет реализовать псевдо-приватные методы и переменные не оправдывает этот подход ни на секунду.
Еще раз недостатки перегруженого конструктора, списком:
* не работает
* значительно больший расход памяти
* работает в десятки-сотни раз медленнее
* методы отсутствуют в прототипе
* методы неправильно определяются через hasOwnProperty
Пользуйтесь тем, что вам удобно и приятно пользователям. Если считаете, что MooTools.Class или любая другая подобная библиотека сделает ваше приложение читабельнее и облегчит поддержку — используйте её! И не обращайте внимание на всяких сами знаете кого, которые кричат про идеологию ДжаваСкрипта (а она, несомненно, прекрасна)
UPD: Этот топик был написан как ответ на сообщение aux:
Я не утверждаю, что подход в фреймворках единственно-верный. Просто не следует избегать таких обёрток, как MooTools.Class, если кто-то сказал вам, что она, видите ли, не соответствует идеологии Javascript или что-то подобное. _
var Foo = new Class({
Extends: Bar,
initialize: function(firstname, lastname) {
this.parent(firstname);
this.lastname = lastname;
},
sayHello: function(){
alert(this.lastname || this.firstname);
}
});
Обёртки в нормальных библиотеках совершенно не противоречат идеологии Javascript и прототипно-ориентированного программирования. Они просто предоставляют удобный интерфейс, алиас для его использования. Конечно, есть библиотеки, которые реализуют «ООП в Javascript» через какие-то черезжопные методы, но сейчас такие во внимание не берем, а рассматриваем их на примере Мутулз.
Например, для конструкции
MyClass = function() {/* constructor */};
MyClass.prototype.firstMethod = function() {/**/};
MyClass.prototype.secondMethod = function() {/**/};
MyClass.prototype.thirdMethod = function() {/**/};
Введен алиас, который позволяет не повторять
MyObject.prototype
. Не обойтись без этой конструкции, а просто не повторять её. Внутри библиотеки будет всё тот же MyClass = new Class({
initialize : function() {/* constructor */},
firstMethod : function() {/**/},
secondMethod: function() {/**/},
thirdMethod : function() {/**/}
});
Следующая конструкция для наследования (заметьте, она полностью соотсветствует идеологии Javascript и «ловится» с помощью
instanceof
)MyAnotherClass = function() {/* constructor */};
var Tmp = function() { }
Tmp.prototype = MyClass.prototype
MyAnotherClass.prototype = new Tmp()
MyAnotherClass.prototype.constructor = MyAnotherClass;
Инкапсулируется в такую простую запись:
MyAnotherClass = new Class({
Extends: MyClass
});
И еще много-много-много. Суть в том, что оно не нарушает идеологию JavaScript. Оно под неё подстраивается и предоставляет удобный интерфейс, а внутри это всё то же самое, что делали бы профессиональные. Ведь идеология прототипно-ориентированного программирования — это не многословность и постоянные упоминания слова «prototype», а невероятная расширяемость.
Перегруженый конструктор
А идеологию нарушает как раз другой, очень вредный и очень популярный подход — перегруженный конструктор:
var MyClass = function() {
/* Начало конструктора */
this.firstMethod = function() {/**/};
this.secondMethod = function() {/**/};
this.thirdMethod = function() {/**/};
/* Конец конструктора, вот такой у нас зашибезный конструктор */
};
var MyAnotherClass = function() {
// Наследование
MyClass.apply(this, arguments);
this.elseOneMethod = function() {/**/};
};
var myAC = new MyAnotherClass();
console.log(myAC instanceof MyClass); // false
Который нельзя наследовать так, чтобы работал
instanceof
, в которой функции создаются каждый раз при создании объекта, из-за чего память течет рекой и рыдает процессор. Вместо того, чтобы создать функцию в одном месте и дать на неё ссылку — будем создавать её каждый раз. Этих функций нету в прототипе (а во встроенных объектах, таких как Array, Number и остальных всё находится именно в прототипе), их нельзя переопределить или получить вне контекста, они неправильно определяются с помощью hasOwnProperty
и работают непозволительно медленно (в сотни раз):var MyClass = function() {
this.method1 = function(){};
};
MyClass.prototype.method2 = function(){};
var myClass = new MyClass;
console.log(myClass.hasOwnProperty('method1')); // true
console.log(myClass.hasOwnProperty('method2')); // false
var Foo = function() {
this.method1 = function(){};
this.method2 = function(){};
this.method3 = function(){};
this.method4 = function(){};
this.method5 = function(){};
this.method6 = function(){};
this.method7 = function(){};
this.method8 = function(){};
this.method9 = function(){};
}
var Bar = function() {};
Bar.prototype.method1 = function(){};
Bar.prototype.method2 = function(){};
Bar.prototype.method3 = function(){};
Bar.prototype.method4 = function(){};
Bar.prototype.method5 = function(){};
Bar.prototype.method6 = function(){};
Bar.prototype.method7 = function(){};
Bar.prototype.method8 = function(){};
Bar.prototype.method9 = function(){};
/**
* Chrome 8
* Foo: 260
* Bar: 26
* Firefox 3.5
* Foo: 22081
* Bar: 158
*/
console.time('Foo');
for (var i = 1000000; i--;) new Foo();
console.timeEnd('Foo');
console.time('Bar');
for (var i = 1000000; i--;) new Bar();
console.timeEnd('Bar');
Я уж молчу про то, что будет в Internet Explorer. Сами проверьте. Можно оставить компьютер включённым на ночь =)
Даже то, что он позволяет реализовать псевдо-приватные методы и переменные не оправдывает этот подход ни на секунду.
Еще раз недостатки перегруженого конструктора, списком:
* не работает
instanceof
в детях* значительно больший расход памяти
* работает в десятки-сотни раз медленнее
* методы отсутствуют в прототипе
* методы неправильно определяются через hasOwnProperty
Вывод
Пользуйтесь тем, что вам удобно и приятно пользователям. Если считаете, что MooTools.Class или любая другая подобная библиотека сделает ваше приложение читабельнее и облегчит поддержку — используйте её! И не обращайте внимание на всяких сами знаете кого, которые кричат про идеологию ДжаваСкрипта (а она, несомненно, прекрасна)
UPD: Этот топик был написан как ответ на сообщение aux:
JS проповедут прототипное ООП, вставлять классовые костыли — не гут. Учите язык и его возможности.
Я не утверждаю, что подход в фреймворках единственно-верный. Просто не следует избегать таких обёрток, как MooTools.Class, если кто-то сказал вам, что она, видите ли, не соответствует идеологии Javascript или что-то подобное. _