Comments 51
Здорово написано. Спасибо! :)
+1
Статья отличная, я как раз вникаю в глубины Javascript и это многое прояснило! Но вот «bisy» просто режет глаз…
-2
Однозначно в закладки, спасибо!
-1
Статья хорошая: ясное изложение, понятные примеры, удачные сравнения. Однозначный плюс.
От себя хотел бы посоветовать выносить константы или константные объекты (как в данном случае defaultOptions) за пределы функции (Timer), желательно перед ней, обернув всё это в анонимную функцию:
Такой подход хорош тем, что:
1) когда вы захотите подправить значения констант, поиск по коду defaultOptions упрощается;
2) объект не создаётся каждый раз и становится доступным для других функций, например, для какой-нибудь changeTimerOptions;
3) появляется возможность динамически менять опции таймера по умолчанию.
Ещё раз, спасибо.
От себя хотел бы посоветовать выносить константы или константные объекты (как в данном случае defaultOptions) за пределы функции (Timer), желательно перед ней, обернув всё это в анонимную функцию:
(function(){
var defaultOptions = { /*константы*/ };
window.Timer = function Timer( options ){
//...
//здесь есть обращение к defaultOptions
//...
}
//...
})();
Такой подход хорош тем, что:
1) когда вы захотите подправить значения констант, поиск по коду defaultOptions упрощается;
2) объект не создаётся каждый раз и становится доступным для других функций, например, для какой-нибудь changeTimerOptions;
3) появляется возможность динамически менять опции таймера по умолчанию.
Ещё раз, спасибо.
+3
С прототипами, учитывая уровень статьи, мне кажется, у вас не очень понятно. Для уверенности дал прочитать эту часть двум знакомым начинающим front-end-рам — они согласились.
Я, помогая в понимании JS, всегда даю читать вот это — лучшего мануала по прототипам и наследованию не встречал.
А статья написано просто замечательно. У вас, должно быть, гуманитарное образование, или явный талант к изложению.
Я, помогая в понимании JS, всегда даю читать вот это — лучшего мануала по прототипам и наследованию не встречал.
А статья написано просто замечательно. У вас, должно быть, гуманитарное образование, или явный талант к изложению.
+3
ну вот, напишешь хорошую статью — обзовут гумном
-1
>лучшего мануала по прототипам и наследованию не встречал.
не советовал бы я читать это, так обычно появляются клоуны, которые потом везде кричат что вы все делаете неправильное ООП в жаваскрипте и есть только уан тру вэй — это вот этот примитив с прототипами, но как правило эти люди не работали ни над чем сложным.
есть отличное видео по этой теме Class Inheritance and Composition Patterns in YUI
не советовал бы я читать это, так обычно появляются клоуны, которые потом везде кричат что вы все делаете неправильное ООП в жаваскрипте и есть только уан тру вэй — это вот этот примитив с прототипами, но как правило эти люди не работали ни над чем сложным.
есть отличное видео по этой теме Class Inheritance and Composition Patterns in YUI
-1
Клоуны появляются не от этого, а от попытки сделать полноценное ООП там, где его не было задумано. С каких это пор фундаментальные знания по языку стали губительными?
Понимать и реализовывать парадигмы так, как хочется/привыкли — личное дело каждого. Нет никаких «тру-вейев» — все ограничивается фантазией.
Но не зная основ прототипного наследования, никогда не напишешь Y.object() или Y.extend() — верно?
Понимать и реализовывать парадигмы так, как хочется/привыкли — личное дело каждого. Нет никаких «тру-вейев» — все ограничивается фантазией.
Но не зная основ прототипного наследования, никогда не напишешь Y.object() или Y.extend() — верно?
0
>Клоуны появляются не от этого
Судя по общению с людьми, появляются именно от таких статей, в которых показывают что такое прототипы, самые базовые конструкции, которые можно с их помощью получить и произносятся слова вроде «Или имитацию «классического» ООП. Ещё чаще это выглядит надругательством над возможностями JS, которое, я уверен, даёт о себе знать с усложнением проектов.»
>Но не зная основ прототипного наследования, никогда не напишешь Y.object() или Y.extend() — верно?
верно, но на звание лучшего мануала по наследованию та статья как-то совсем не тянет.
Судя по общению с людьми, появляются именно от таких статей, в которых показывают что такое прототипы, самые базовые конструкции, которые можно с их помощью получить и произносятся слова вроде «Или имитацию «классического» ООП. Ещё чаще это выглядит надругательством над возможностями JS, которое, я уверен, даёт о себе знать с усложнением проектов.»
>Но не зная основ прототипного наследования, никогда не напишешь Y.object() или Y.extend() — верно?
верно, но на звание лучшего мануала по наследованию та статья как-то совсем не тянет.
-1
Прекрасно! Вы настаиваете на ошибочной теории и поливаете грязью тех, кто старается вернуть новичков к правильному пути. Создание методов в конструкторе — это ересь. Она нарушает идеологию ооп в общем и идеологию JS в частности. В конструкторе должно происходить конструирование экземпляра (да, такая уж тафтология), а не всего класса, как у вас. Т.Е. очень грубо говоря — чем этот экземпляр отличается от класса в целом. А у подхода с перегруженным конструктором — всё смешано в кучу. Самое отвратительное, что люди даже не понимают логики такого подхода. Посмотрите то же самое на php и почувствуйте всю отвратительность:
Так почему на php такое никто не напишет, а над JS все издеваются как хотят?
<?
class Timer {
function __construct ($options) {
$defaultOptions = array(
'delay' => 20,
'stopFrame' => 0,
'loop' => true
);
foreach ($defaultOptions as $option => $values) $this[$option] = $option ? ($options[$option] || $defaultOptions[$option]) : $defaultOptions[$option];
$this->start = function() {
// code
};
$this->setActiveFrameElement = function( frameNumber ){
// code
};
$this->toString = function() {
// code
}
$this->setTask = function( new_task ) {
// code
}
$this->getKeyFrames = function(){
return $keyFrames;
}
$this->getTask = function(){
return $task;
}
}
}
Так почему на php такое никто не напишет, а над JS все издеваются как хотят?
+5
WUT? :)
>Создание методов в конструкторе — это ересь
Я где-то говорил про создание методов в конструкторе?
>В конструкторе должно происходить конструирование экземпляра ..., а не всего класса, как у вас.
У вас замечательные способности читать чужие мысли, но спешу вас разочаровать, ваша способность иногда обманывает вас :)
Еслиб вы потрудились взглянуть на видео, которое я привёл первым комментарием, может тогда хоть немного дошло то о чём я говорил. Я же не говорю что прототипы — это зло, я просто говорю что в сложном проекте недостаточно Object.create
>Создание методов в конструкторе — это ересь
Я где-то говорил про создание методов в конструкторе?
>В конструкторе должно происходить конструирование экземпляра ..., а не всего класса, как у вас.
У вас замечательные способности читать чужие мысли, но спешу вас разочаровать, ваша способность иногда обманывает вас :)
Еслиб вы потрудились взглянуть на видео, которое я привёл первым комментарием, может тогда хоть немного дошло то о чём я говорил. Я же не говорю что прототипы — это зло, я просто говорю что в сложном проекте недостаточно Object.create
0
К сожалению, у меня закрыт доступ к ТыТрубе сейчас.
Я так понял, что вы поддерживаете позицию автора на счёт использовния перегружённого конструктора. Если ошибся, то поясните свою позицию лично, пожалуйста, без видео. Можно в двух словах.
Я так понял, что вы поддерживаете позицию автора на счёт использовния перегружённого конструктора. Если ошибся, то поясните свою позицию лично, пожалуйста, без видео. Можно в двух словах.
0
Моя позиция в том что я заметил как вокруг бегает много интересных людей, которые узнали про Object.create и когда они видят нечто вроде YUI Base, то начинают говорить о том какая это Java и все кто это используют — полные идиоты и ничего не понимают в жаваскрипте.
Благо разработчики YUI отлично понимают плюсы и недостатки разных подходов и используют наиболее подходящие инструменты для решения различных задач.
Y.Object() // Object.create
Y.extend()
Y.augment()
Plugins
Class Extensions
Благо разработчики YUI отлично понимают плюсы и недостатки разных подходов и используют наиболее подходящие инструменты для решения различных задач.
Y.Object() // Object.create
Y.extend()
Y.augment()
Plugins
Class Extensions
0
оу, так вы на счёт классовых обёрток? Ну в этом я с вами согласен
+1
Я пока только учу JS, но такая запись
this[option] = options? (options[option] || defaultOptions[option]): defaultOptions[option];
не позволит установить значения опций как false, 0, '' (пустая строка).
this[option] = options? (options[option] || defaultOptions[option]): defaultOptions[option];
не позволит установить значения опций как false, 0, '' (пустая строка).
+3
Вообще, немного «корявый» способ, лучше вынести эту логику в отдельную функцию:
Давайте лучше рассмотрим пример:
var extend = function(to, from) {
for (var key in from)
if (from.hasOwnProperty(key))
to[key] = from[key];
return to;
};
//........................................................................
var options = {
foo: 1,
bar: 2
}
// Default options
var params = extend({
foo: 0
}, options);
params.foo //1
params.bar //2
//public var defaultOptions
Давайте лучше рассмотрим пример:
var Foo = new function() {
//private
var private = 1;
var Foo = function() {
//...
};
//public
Foo.prototype = {
constructor: Foo,
foo: 1,
bar: function(param) {
return this.foo + param + private;
}
};
return Foo;
};
var object = new Foo;
object.foo; // 1
object.bar(1); // 3
+1
Относительно наследования:
var Extend = function(child, parent) {
for (var key in parent) {
if (parent.hasOwnProperty(key))
child[key] = parent[key];
}
var __new__ = function() {
this.constructor = child;
}
__new__.prototype = parent.prototype;
child.prototype = new __new__();
child.__super__ = parent.prototype;
return child;
};
function A(value) {
this.set = value;
};
A.prototype.get = function() {
return this.set;
};
function B(value) {
this.set = value;
};
Extend(B, A);
alert(new A(1).get()); // 1
alert(new B(2).get()); // 2
function C(value) {
this.set = value;
};
C.prototype.get = function(value) {
return B.__super__.get.call(this, arguments);
};
alert(new C(3).get()); // 3
0
Верно, ошибка моя.
Спасибо, что заметили.
Спасибо, что заметили.
0
исправил на
for(var option in defaultOptions) this[option] = options && options[option]!==undefined ? options[option] : defaultOptions[option];
0
Отличная статья! Отдельное спасибо за юмор :)
0
Ужасная статья! Здесь показано, как нельзя программировать. Во-первых, нарушается SRP. Во-вторых, неправильно используется наследование (впрочем, я вообще за то, чтобы избегать наследования как такового), хотя тут же можно отослать и к SRP. В-третьих, нарушается инкапсуляция на каждом шагу (например, что произойдёт, если таймер уже работает, а у него поменяют свойства stopFrame, или что если написать timer.getTask()[0] = foo). В-четвёртых, странноватые имена для некоторых сущностей (например, task там, где логичнее было бы tasks или schedule).
+1
Статья учебная, пример в ней — тоже.
То о чем вы говорите, решается на стадии отладки. И еще миллион возможных багов…
То о чем вы говорите, решается на стадии отладки. И еще миллион возможных багов…
0
Проблемы, о которых я говорю, не решаются на стадии отладки. Они решаются на стадии рефакторинга. Вот только рефакторинг может быть разным. Где-то намеренно оставляют технический долг, потому что здесь и сейчас времени нет. А где-то люди по незнанию городят вот такое. Если бы сразу не городили, было бы лучше. Если уж показывать, как реализовано ООП в javascript, то надо заодно и писать о том, где его уместно использовать и как это правильно делается.
0
Спасибо за труд. Только пример наследования и объяснение прототипов я бы делал без extend.
Например, опишем родителя:
/**
* constructor
*/
var Foo = function() {
/** type {number} */
this.param = 1;
}
/**
* return {number}
*/
Foo.prototype.getParam = function() {
return this.param;
}
Функция, реализующая наследование:
/**
* Реализует прототипное наслдование.
* Взял из Google Closure Library.
* @param {Function} childCtor Конструктор потомка
* @param {Function} parentCtor Конструктор родителя
*/
var inherits = function(childCtor, parentCtor) {
/**
* Создаем пустой конструктор
* constructor
*/
function tempCtor() {};
// Складываем прототип родителя в прототип временного
// конструктора
tempCtor.prototype = parentCtor.prototype;
// В superClass кладем ссылку на прототип родителя.
// Нужно чтобы вызывать методы родителя.
childCtor.superClass = parentCtor.prototype;
// В прототип ребенка кладем экземпляр пустого
// конструтора. Не забываем, что все методы родитля
// лежат в его прототипе, а значит передадутся
// ребенку
childCtor.prototype = new tempCtor();
// Запоминаем конструктор
childCtor.prototype.constructor = childCtor;
};
Теперь ребенка:
/**
* constructor
* @extends
*/
var Bar = function() {
// в superClass лежит ссылка на прототип родителя,
Foo.call(this);
/** type {number} */
this.otherParam = 2;
}
// Наследуемся от Foo, код наследования чуть выше.
inherits(Bar, Foo);
/**
* return {number}
*/
Bar.prototype.getOtherParam = function() {
return this.otherParam;
}
А теперь посмотрим, что получилось:
var foo = new Foo();
var fooParam = foo.getParam(); // 1
var bar = new Bar();
var barParam = bar.getParam(); // 1
var barOtherParam = bar.getOtherParam(); // 2
Объявлять методы внутри других методов или конструтора с помощью
this.myMethod = function() {/*… */};
не очень хорошо, так как они будут во всех экземплярах создаваться заново, а не ссылаться на функцию в прототипе. По возможности этого надо избегать.
Я понимаю, подход плох тем, что неудобно скрывать методы, делать их по настоящему приватными. Я в коде использую соглашеие, что приватные методы начинаются с _. Спасает только то, что на боевом сервере весь код выполняется в замыкании. Зато не нужно перекладывать метода из родителя в ребянка for..in
Например, опишем родителя:
/**
* constructor
*/
var Foo = function() {
/** type {number} */
this.param = 1;
}
/**
* return {number}
*/
Foo.prototype.getParam = function() {
return this.param;
}
Функция, реализующая наследование:
/**
* Реализует прототипное наслдование.
* Взял из Google Closure Library.
* @param {Function} childCtor Конструктор потомка
* @param {Function} parentCtor Конструктор родителя
*/
var inherits = function(childCtor, parentCtor) {
/**
* Создаем пустой конструктор
* constructor
*/
function tempCtor() {};
// Складываем прототип родителя в прототип временного
// конструктора
tempCtor.prototype = parentCtor.prototype;
// В superClass кладем ссылку на прототип родителя.
// Нужно чтобы вызывать методы родителя.
childCtor.superClass = parentCtor.prototype;
// В прототип ребенка кладем экземпляр пустого
// конструтора. Не забываем, что все методы родитля
// лежат в его прототипе, а значит передадутся
// ребенку
childCtor.prototype = new tempCtor();
// Запоминаем конструктор
childCtor.prototype.constructor = childCtor;
};
Теперь ребенка:
/**
* constructor
* @extends
*/
var Bar = function() {
// в superClass лежит ссылка на прототип родителя,
Foo.call(this);
/** type {number} */
this.otherParam = 2;
}
// Наследуемся от Foo, код наследования чуть выше.
inherits(Bar, Foo);
/**
* return {number}
*/
Bar.prototype.getOtherParam = function() {
return this.otherParam;
}
А теперь посмотрим, что получилось:
var foo = new Foo();
var fooParam = foo.getParam(); // 1
var bar = new Bar();
var barParam = bar.getParam(); // 1
var barOtherParam = bar.getOtherParam(); // 2
Объявлять методы внутри других методов или конструтора с помощью
this.myMethod = function() {/*… */};
не очень хорошо, так как они будут во всех экземплярах создаваться заново, а не ссылаться на функцию в прототипе. По возможности этого надо избегать.
Я понимаю, подход плох тем, что неудобно скрывать методы, делать их по настоящему приватными. Я в коде использую соглашеие, что приватные методы начинаются с _. Спасает только то, что на боевом сервере весь код выполняется в замыкании. Зато не нужно перекладывать метода из родителя в ребянка for..in
+2
Убедительная просьба к автору этой статьи и к другим авторам статей по JS: используйте правильную терминологию. Не вводите новичков в заблуждение. new — это оператор, а не директива. timer — это экземпляр конструктора Timer, а не объект класса (хорошо что хоть не типа) Timer.
Ну и самый важный момент: настоящее ООП в JS есть! После этих строк читать дальше желание отпало.
Не хочу быть занудой, но видеть такое почти в каждой статье уже порядком надоело.
Ну и самый важный момент: настоящее ООП в JS есть! После этих строк читать дальше желание отпало.
Не хочу быть занудой, но видеть такое почти в каждой статье уже порядком надоело.
+3
Во, я тоже после пассажа про «настоящее ООП» читать перестал. Раздражает вот это непреодолимое желание сделать себе велосипедные заборы и коровники java-style в яваскрипте.
+2
Не хотите быть занудой — не нудите.
Надоело не в каждой статье про «настоящее ООП» читать, а камменты к этим статьям в вашем стиле.
Надоело не в каждой статье про «настоящее ООП» читать, а камменты к этим статьям в вашем стиле.
0
Хорошо, new — это оператор, но в данном случае можно воспринимать и как директиву, предписывающую функции выполниться особым образом, это улучшает понимание.
timer — не объект класса?
Конечно. Я ведь несколько раз указал условность понятия «класс», даже в заголовке.
На мой взгляд, такие «безупречные» словесные конструкции как «экземпляр конструктора» напрочь отбивают понимание сути. Уж извините, писал, как считал более понятным.
С интересом буду ожидать и вашу статью на тему «ООП в JS есть»…
timer — не объект класса?
Конечно. Я ведь несколько раз указал условность понятия «класс», даже в заголовке.
На мой взгляд, такие «безупречные» словесные конструкции как «экземпляр конструктора» напрочь отбивают понимание сути. Уж извините, писал, как считал более понятным.
С интересом буду ожидать и вашу статью на тему «ООП в JS есть»…
0
Понимание — вещь относительная.
Мне, к примеру, понятнее будет знать, что оператор new вызывает функцию, а не предписывает ей что-то. Яркий тому пример:
Скобки необязательны так как оператор сам всё сделает.
По поводу термина «Класс». Если вам удобнее использовать этот термин — никто не против, но необходимо явно оговориться что вы понимаете под этим, что бы дальнейшее чтение никого не сбивало с толку. Необходимо — потому что сам термин пришел из других языков. Кавычки каждый может понять по-своему.
«Экземпляр конструктора» — это и есть суть. Если вы считаете такое определение непонятным — расскажите о нем более развернуто, а не ищите ему замену.
Писать ещё одну статью про ООП в JS не вижу смысла, уже всё написано.
Мне, к примеру, понятнее будет знать, что оператор new вызывает функцию, а не предписывает ей что-то. Яркий тому пример:
new functionName;
Скобки необязательны так как оператор сам всё сделает.
По поводу термина «Класс». Если вам удобнее использовать этот термин — никто не против, но необходимо явно оговориться что вы понимаете под этим, что бы дальнейшее чтение никого не сбивало с толку. Необходимо — потому что сам термин пришел из других языков. Кавычки каждый может понять по-своему.
«Экземпляр конструктора» — это и есть суть. Если вы считаете такое определение непонятным — расскажите о нем более развернуто, а не ищите ему замену.
Писать ещё одну статью про ООП в JS не вижу смысла, уже всё написано.
0
Статья очень плохая. Просто сборник дурных практик.
Я понимаю, мы 10 лет назад долго писали такой пи**ец-код, пока не разобрались — просто потому что нормальной документации по теме вообще не было.
Но сейчас-то?
Почитайте MDN, загляните в реализацию наследования в node.js и в Google Closure Library.
Не городите ужасов, пожалуйста.
Я понимаю, мы 10 лет назад долго писали такой пи**ец-код, пока не разобрались — просто потому что нормальной документации по теме вообще не было.
Но сейчас-то?
Почитайте MDN, загляните в реализацию наследования в node.js и в Google Closure Library.
Не городите ужасов, пожалуйста.
+1
Пожелание к 3-м последним комментаторам:
С интересом буду ожидать ВАШУ статью на тему "ООП в JS есть!"…
С интересом буду ожидать ВАШУ статью на тему "ООП в JS есть!"…
+2
Да, пожалуй, придется )))
Денис, без обид, но Вы действительно не слишком хорошо разобрались в теме.
А здесь очень много новичков, которые этого просто не видят.
И мало JS-разработчиков с серьезным опытом в IT за пределами создания прикольной анимации и плагинов к jQuery. Таких вообще мало, к сожалению.
Так что не принимайте восторженные отзывы слишком серьезно.
Лучше поговорите с кем-нибудь, кто в теме давно, всерьез и надолго.
Денис, без обид, но Вы действительно не слишком хорошо разобрались в теме.
А здесь очень много новичков, которые этого просто не видят.
И мало JS-разработчиков с серьезным опытом в IT за пределами создания прикольной анимации и плагинов к jQuery. Таких вообще мало, к сожалению.
Так что не принимайте восторженные отзывы слишком серьезно.
Лучше поговорите с кем-нибудь, кто в теме давно, всерьез и надолго.
0
Я и не обижаюсь. И на безупречное знание темы не претендую.
А Вы, в теме давно? Вам и слово.
По сути то Вы правы: есть ООП! Потому, что в первую очередь оно есть… в душе программиста, а значит и везде где он пожелает ему следовать. Об этом же и статья.
А вот в спецификации нет.
Но душа то нам важнее. ;-)
А Вы, в теме давно? Вам и слово.
По сути то Вы правы: есть ООП! Потому, что в первую очередь оно есть… в душе программиста, а значит и везде где он пожелает ему следовать. Об этом же и статья.
А вот в спецификации нет.
Но душа то нам важнее. ;-)
0
А вот в спецификации нет.
Как это нет?
Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties. Objects are created by using constructors in new expressions...
4.2.1 Objects
0
Похоже, для Вас это вопрос веры, а не точности тех. реализации.
В священные войны я не вступаю. :)
В священные войны я не вступаю. :)
0
Вы не просто вступаете в священные войны. Вы их развязываете!
0
Так это видят только те, кто хочет воевать. :)
-1
То есть вы хотите воевать и потому вам кажется, что monolithed холиварит? Интересная логика.
0
Денис, ну что за детский сад: «С интересом буду ожидать ВАШУ статью на тему «ООП в JS есть!»»? Не обязательно быть поваром, чтоб понять, что блюдо — не вкусное. Это критика, причем обоснованная, не нужно скатываться до «сперва добейся сам».
0
На момент публикации статьи очень не кстати выяснилось, что на сайте denis-or-love.narod.ru где пример, засел хулиганский js скрипт.
Скрипт я «выпилил», но плашка с предупреждением от яндекс пока осталась.
Скрипт я «выпилил», но плашка с предупреждением от яндекс пока осталась.
0
Ужасная статья, к третьему абзацу понятно, что ООП в JavaScript мне не нужен и лучше пойти какао попить и не тратить время. Очень много воды, вернее весь текст — вода с кусочками кода, чтобы показать что статья техническая.
Настоящего ООП в JS нет! Как выше заметили местами код ужасен.
Писать свою статью не буду, ибо логика сначала сам сделай, а потом критикуй не для меня :)
Настоящего ООП в JS нет! Как выше заметили местами код ужасен.
Писать свою статью не буду, ибо логика сначала сам сделай, а потом критикуй не для меня :)
-2
Разумеется.
Критикуют одни, а созидают другие. :)
Статья написана не ради плюсиков или пустого тролле-трепа, а ради реальной пользы, которую она уже принесла и продолжает нести.
Спасибо, что читаете.
Критикуют одни, а созидают другие. :)
Статья написана не ради плюсиков или пустого тролле-трепа, а ради реальной пользы, которую она уже принесла и продолжает нести.
Спасибо, что читаете.
0
Какую пользу она приносит? Практическую? Да, после вашей статьи появится на еще одного говнокодера больше, который не знает, что ООП в JS есть. Он будет держаться молодцом, зарабатывать деньги, но будет оставаться безграмотным, не знающим элементарнейших вещей из своей области. Не обольщайтесь хорошими оценками к посту, я так же, как и вы могу писать сатьи на тему квантовой механики, имея знания только «по верхам» и доставляя радость людям, которые в ней разбираются немногим хуже меня.
0
Sign up to leave a comment.
Javascript: ООП, прототипы, замыкания, «класс» Timer.js