Comments 36
… создавая сложные джаваскрипт-приложения, уже решает эту проблему каким-то определенным образом без фреймворков
Вопрос зачем? Зачем нужно создавать сложные js-приложения, не используя сторонние фреймворки? Поймите правильно, я против того, чтобы в каждое мало-мальское web-app пихали все подряд библиотеки и все это превращалось в что-то монструозное, но если приложение действительно достаточно сложное, то просто моделью вы все равно не обойдетесь, а следовательно лучше сразу использовать какую-нибудь хорошо известную связку.
Текущая ситуация с JS мне начинает напоминать ситуацию с PHP. Сделал свой велосипед — зачем? Да, я тоже не рад использованию везде и вся миллионов фреймворков. Особенно бесит, что сейчас уже «программируют на jQuery», а не на JS. Но ответ на Ваш вопрос «зачем?» — чтобы учиться. Хороший велосипед — перенять чужой опыт. Плохой — тоже перенять чужой опыт и не повторять ошибки.
Данное решение выглядит вполне хорошо, так почему этому не быть микрофреймворком. Лично мне данный проект внешне очень понравился, хочу попробовать в связке с KnockoutJS. Мне не хватает чего-то удобного для работы с моделью
Я соглашусь с вами, Сергей: без фреймворка действительно не обойтись. Миниатюрные же библиотеки в моих глазах хороши тем, что из них можно скомпоновать «свой» фреймворк, разработать свой способ, не принимая навязываемые другими фреймворками конвенции и ограничения. Если иметь ряд инструментов, каждый из которых исключительно хорош в своем узком деле, можно, построив из них систему, выйти за рамки и создать более качественный продукт. Как пример вспоминаются юниксы.
Я также очень настороженно отношусь к новым библиотекам и любой новый способ/подход, равно как и инструмент, конечно, должен пройти проверку боем и проверку временем. Model.js здесь не исключение.
Я также очень настороженно отношусь к новым библиотекам и любой новый способ/подход, равно как и инструмент, конечно, должен пройти проверку боем и проверку временем. Model.js здесь не исключение.
Какой-то у вас сахар несладкий
Почему не так:
Вообще круто. developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind Переопределять стандартный метод вместо того чтобы использовать общепринятые on или addEventListener
Это разве синтаксический сахар?
var Note = new Model('Note', function () {
this.attr('id!', 'number');
this.attr('title', 'string', 'nonempty');
this.attr('text', 'string');
});
Почему не так:
var Note = new Model({
'id!' : 'number',
'title': {
type: 'string' // или String
validator: 'non-empty'
},
'text': 'string'
});
note.bind(eventName, handler) «вешает» обработчик. Кстати говоря, повесить обработчик любого события можно не только на отдельную сущность, но и на все сущности класса (Note.bind).
Вообще круто. developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind Переопределять стандартный метод вместо того чтобы использовать общепринятые on или addEventListener
this.attr('title', 'string', 'nonempty', [ 'minLength', 6 ]);
Это разве синтаксический сахар?
Спасибо, вы задали интересный вопрос. Вообще, сахар-не-сахар — это все субъективно, но…
Смотрите, конфигурационную функцию конструктор моделей получает не просто так. Сейчас в ее контексте есть только метод
Форма же записи объектом, которая вам больше по душе, несомненно хороша и более привычна. Но пример, который вы привели, с одной стороны немного избыточен, а с другой — не все отражает:
1. Тип нам нужен только чтобы его проверить, и поэтому ничего страшного нет в том, чтобы просто записать валидатор с названием типа, не делая особый синтаксический акцент на том, что это именно тип. Получается, вы немного усложнили, а не упростили.
2. Валидатор — не один — их может быть любое количество, как того может требовать логика нашего приложения. Каждый из валидаторов, когда проверяется значение, если возвращает ошибку, останавливает всю цепочку за ним.
В этом примере мы сперва проверяем не null ли, затем строка ли, затем не пуста ли и затем не меньше ли 6 символов в длину. Каждый их этих валидаторов может вернуть нам код своей ошибки и остановить на этом проверку конкретного значения. Код ошибки, который он возвратит, может что-то означать в нашем приложении. Даже то, что
Стоит также помнить и о том, что валидаторы могут принимать атрибуты, как в случае с
Если учесть изложенные нюансы и записать в форме объекта это описание, все становится очень похожим на тот пример, который вы критикуете.
Но нам нужна эта конфигурационная функция,— выше я объяснил почему,— и поэтому форма объявления атрибута при помощи
По поводу метода
Смотрите, конфигурационную функцию конструктор моделей получает не просто так. Сейчас в ее контексте есть только метод
this.attr(attrName, validator[, validator, …])
, но в будущем появятся и другие методы, при помощи которых будет описываться модель. Например, this.validates(function () {…})
, которая должна бы валидировать модель вцелом после проверки значений атрибутов. Есть и другие задумки.Форма же записи объектом, которая вам больше по душе, несомненно хороша и более привычна. Но пример, который вы привели, с одной стороны немного избыточен, а с другой — не все отражает:
1. Тип нам нужен только чтобы его проверить, и поэтому ничего страшного нет в том, чтобы просто записать валидатор с названием типа, не делая особый синтаксический акцент на том, что это именно тип. Получается, вы немного усложнили, а не упростили.
2. Валидатор — не один — их может быть любое количество, как того может требовать логика нашего приложения. Каждый из валидаторов, когда проверяется значение, если возвращает ошибку, останавливает всю цепочку за ним.
this.attr('title', 'nonnull', 'string', 'nonempty', [ 'minLength', 6 ]);
В этом примере мы сперва проверяем не null ли, затем строка ли, затем не пуста ли и затем не меньше ли 6 символов в длину. Каждый их этих валидаторов может вернуть нам код своей ошибки и остановить на этом проверку конкретного значения. Код ошибки, который он возвратит, может что-то означать в нашем приложении. Даже то, что
nonempty
и [ 'minLength', 6 ]
стоят рядом может иметь в нашем приложении специальный смысл (я имею ввиду, что в принципе nonempty
можно и не указывать рядом с [ 'minLength', 6 ]
).Стоит также помнить и о том, что валидаторы могут принимать атрибуты, как в случае с
minLength
или in
.Если учесть изложенные нюансы и записать в форме объекта это описание, все становится очень похожим на тот пример, который вы критикуете.
var Note = new Model({
'id!' : 'number',
'title': [ 'nonnull', 'string', 'non-empty', [ 'minLength', 6 ] ],
'text': 'string'
});
Но нам нужна эта конфигурационная функция,— выше я объяснил почему,— и поэтому форма объявления атрибута при помощи
this.attr
все же предпочтительней.По поводу метода
bind
, то он стал стандартным только в JS 1.8.5 (в современных браузерах с марта 2011 года, начиная с ФФ4), в то время, как Model.js нацелена на JS 1.5 (c ноября 2000 года в абсолютном большинство современных браузеров). Но вы правы, в будущем этому нюансу стоит уделить больше внимания. А пока, в ближайших версиях, возможно, и стоит создать алиас на слово on
, которое сделали популярным последние версии jQuery и Backbone.С точки зрения «сахарности» можно иногда и усложнить, в угоду читаемости. Например:
Несмотря на то, что тип это просто валидатор, можно для него сделать отдельное поле (естественно, как опцию, а не жесткое правило). Для валидаторов можно сделать два поля — validator и validators. Вот это и есть сахар. Причем обратывать эти поля можно одним и тем же кодом, то есть использовать их как синонимы (ну точне брать валидаторы из всех и объединять в массив).
Для аргументов валидаторов вы нашли плохое решение, потому что элементы массива равноправны, а названия валидатора и аргументы — нет. Понятно, что они нужны, но в итоге совершенно нечитаемо.
Насчет конфигурационной функции — не понятно, почему то же самое нельзя делать снаружи:
Если вас так волнует поддержка старых браузеров, то весьма странно видеть использование __proto__,__defineGetter__ и __defineSetter__, которые вообще не являются стандартными.
var Note = new Model({
'text': {
'name' : {
type: 'string',
validators: []
}
}
});
Несмотря на то, что тип это просто валидатор, можно для него сделать отдельное поле (естественно, как опцию, а не жесткое правило). Для валидаторов можно сделать два поля — validator и validators. Вот это и есть сахар. Причем обратывать эти поля можно одним и тем же кодом, то есть использовать их как синонимы (ну точне брать валидаторы из всех и объединять в массив).
Для аргументов валидаторов вы нашли плохое решение, потому что элементы массива равноправны, а названия валидатора и аргументы — нет. Понятно, что они нужны, но в итоге совершенно нечитаемо.
Насчет конфигурационной функции — не понятно, почему то же самое нельзя делать снаружи:
var Note = new Model('Note', function () {
}).attr('id!', 'number').validates(...)
По поводу метода bind, то он стал стандартным только в JS 1.8.5 (в современных браузерах с марта 2011 года, начиная с ФФ4), в то время, как Model.js нацелена на JS 1.5
Если вас так волнует поддержка старых браузеров, то весьма странно видеть использование __proto__,__defineGetter__ и __defineSetter__, которые вообще не являются стандартными.
Спасибо вам за мнение. Объективно, если усложнять, то это уже не «сахар». Я также не согласен с вами в том, что многоэтажные объекты легче читаются. Но, вообще, конечно, удобство — категория субъективная. Думаю, вы согласитесь, что тратить время ну пустые споры не имеет смысла.
Есть другой момент. Из ряда
Буду признателен, если вы сможете объяснить почему так происходит.
Есть другой момент. Из ряда
__proto__
, __defineGetter__
и __defineSetter__
нестандартным в JS 1.5 есть только __proto__
. Присмотритесь к коду. Использование __proto__
в 2 местах — это всего лишь перестраховка от кое-каких особенностей современных браузеров: если вообще удалить __proto__
, смысл не пострадает, но вот в последних хромах (напр. версии 24.0.1312.70) прототипная цепочка почему-то не установится (слетит ровно 75 тестов).Буду признателен, если вы сможете объяснить почему так происходит.
Для начала расскажите, чего вы хотите добиться такими конструкциями:
Если cls это не функция, то установка prototype ничего не делает. Если cls это функция, то устанавливая __proto__ вы отрубаете Function.prototype. Отличный пост habrahabr.ru/post/140810/, еще dailyjs.com/2012/11/26/js101-proto/.
Если вы хотите, чтобы у конструктора были те же методы, что и у порождаемых им объектах (т. е. их прототипа), нужно скопировать их из прототипа в конструктор.
cls.prototype = cls.__proto__ = private.Class.prototype;
Если cls это не функция, то установка prototype ничего не делает. Если cls это функция, то устанавливая __proto__ вы отрубаете Function.prototype. Отличный пост habrahabr.ru/post/140810/, еще dailyjs.com/2012/11/26/js101-proto/.
Если вы хотите, чтобы у конструктора были те же методы, что и у порождаемых им объектах (т. е. их прототипа), нужно скопировать их из прототипа в конструктор.
Да, вы правы. Они присутствуют не во всех реализациях JS 1.5, а только в сишных.
JavaScript writers can now add getters and setters to their objects. This feature is available only in the C implementation of JavaScript.developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.5
ведь чтобы ей стать «взрослой» библиотекой, нужно проделать еще немало работыЧто бы ей в конце-концов стать backbone.js надо действительно проделать немало работы
Смотрели component.model?
Никого не слушайте (имею ввиду критику без аргументов). Вы сделали несомненно очень крутую и полезную библиотеку. Это естественно, что у нее есть какие-то «детские болячки», и я надеюсь, что в скором времени вы ее вылечите и вырастите в легковесный и удобный рабочий инструмент. Удачи.
В качестве типа атрибута можно использовать другую модель?
Да, можно. Нужно создать валидатор, который проверит есть ли значение аттрибута сущностью другой модели. Сейчас нет какого-то красивого метода сущности для этой цели, поэтому нужно извернуться вот так:
Вообще, спасибо вам за идею — этот момент доработаем в ближайшей версии.
На ум пока пришла такая вот форма:
var Author = new Model('Author', function () {…});
var Comment = new Model('Comment', function () {
this.attr('author', function (author) {
if (author.constructor.className != 'Author') return 'wrongtype';
});
this.attr('text', 'string');
});
Вообще, спасибо вам за идею — этот момент доработаем в ближайшей версии.
На ум пока пришла такая вот форма:
var Author = new Model('Author', function () {…});
var Comment = new Model('Comment', function () {
this.attr('author', 'Author');
this.attr('text', 'string');
});
А наследовать модели друг от друга нельзя?
В целом все довольно просто, но вешать глобальный обработчик на класс, что бы изменять инстанс по дефолту крайне витиеватое решение. Не очень приятно наследование через callback. Что бы добавить свойств, хотелось бы иметь возможность их явно указать, например, их можно передавать объектом.
В Backbone прекрасная механика наследования, за счет этого, что бы задать дефолтные значения, достаточно передать свойство default. Тут же появляется возможность переопределять конструктор и функцию инициализации. Расширить валидацию свойств не проблема.
Так же для остлеживания создания моделей на глобальном уровне, достаточно создать коллекцию, что даёт более обширные возможности с точки зрения выборок. Но обучение дело золотое, не спорю.
В Backbone прекрасная механика наследования, за счет этого, что бы задать дефолтные значения, достаточно передать свойство default. Тут же появляется возможность переопределять конструктор и функцию инициализации. Расширить валидацию свойств не проблема.
Так же для остлеживания создания моделей на глобальном уровне, достаточно создать коллекцию, что даёт более обширные возможности с точки зрения выборок. Но обучение дело золотое, не спорю.
Спасибо. Вы знаете, в будущих версиях синтаксис объявления атрибутов наверняка будет доработан. Вы ведь правы: сейчас нужно много движений, чтобы установить значение по умолчанию, да и функция инициализации и вправду не помешала бы.
По поводу выборок также есть задумки. В текущей же версии вопрос регистра сущностей и методов класса моделей, которые как-то бы с этим регистром работали, умышленно обойден. Но не могу не согласиться, это и вправду нужная функциональность.
По поводу выборок также есть задумки. В текущей же версии вопрос регистра сущностей и методов класса моделей, которые как-то бы с этим регистром работали, умышленно обойден. Но не могу не согласиться, это и вправду нужная функциональность.
Пожалуйста, не пишите так:
у jq есть замечательный параметр context
Биндить скоупы нужно всегда, для этого в jq есть метод $.proxy(fn,scope,args). хорошая статья про скоупы
var note = this;
return $.ajax({
type: 'PUT',
url: '/notes/'+this.data.id,
data: this.data(),
dataType: 'json'
}).done(function (json) {
note._persist();
});
у jq есть замечательный параметр context
return $.ajax({
type: 'PUT',
url: '/notes/'+note.data.id,
data: note.data(),
dataType: 'json',
context: this,
}).done(function (json) {
this._persist();
});
Биндить скоупы нужно всегда, для этого в jq есть метод $.proxy(fn,scope,args). хорошая статья про скоупы
На мой вкус не хватает коллекций и сериализации в json. А так достаточно неплохо получилось.
Нитпик: «State of the art» — это высшее достижение ремесла на текущий момент. А не «незаконченный набросок», в каком качестве эта фраза, по всей видимости, используется в этом тексте. В остальном — кул!
Sign up to leave a comment.
Работа с моделями данных в javascript