(Архив) Matreshka.js — MK.Object

  • Tutorial
Статья устарела. В новой документации содержится самая актуальная информация из этого поста. См. Matreshka.Object.


В предыдущих статьях мы познакомились с общими принципами Матрешки: привязка элементов, события, наследование. В конце предыдущей статьи я задал себе вопрос: «Как разграничить состояние приложения (показать ли пользователю пароль) и данные приложения (логин, пароль, «запомнить меня»)».

Класс, который нам в этом поможет, называется MK.Object, который наследуется от класса Matreshka. Идея проста: у нас есть множество ключей, отвечающих за данные в экземпляре класса и мы считаем, что остальные свойства отвечают лишь за состояние приложения и не являются бизнес моделью.

Как устроено множество ключей
За множество ключей отвечает псевдоприватное свойство ._keys, которое является объектом со значениями, которые нам безразличны. Массив бы нам не подошел, потому что, перед добавлением нового ключа надо было бы проверять, есть ли ключ в массиве, а при удалении, пришлось бы узнавать индекс, затем сдвигать следующие элементы. В случае объекта, мы получаем полноценное множество строк, для добавления нового ключа не нужно проверять его наличие, а для удаления требуется лишь вызов оператора delete.


Для того, чтоб установить свойство, которое отвечает за данные, используется метод .jset:
var mkObject = new MK.Object();
mkObject.jset( 'a', 1 );
console.log( mkObject.toJSON() ); // { a: 1 }


Документация к .jset: finom.github.io/matreshka/docs/Matreshka.Object.html#jset
Документация к .toJSON: finom.github.io/matreshka/docs/Matreshka.Object.html#toJSON
Теперь можем работать с новым свойством как обычно:
var mkObject = new MK.Object();
mkObject.jset( 'a', 1 );
mkObject.a = 2;
console.log( mkObject.toJSON() ); // { a: 2 }

В том числе, мы можем использовать унаследованные от класса Matreshka методы:
mkObject.bindNode( 'a', '.my-element' );
mkObject.on( 'change:a', handler );

Если мы установим свойство, не добавив его ключ в множество ключей, в результате работы метода .toJSON мы не увидим этого свойства:
var mkObject = new MK.Object();
mkObject.jset( 'a', 1 );
mkObject.b = 3;
console.log( mkObject.toJSON() ); // { a: 1 }

Можно добавить ключи в список ключей, используя метод .addJSONKeys
Дока: finom.github.io/matreshka/docs/Matreshka.Object.html#addJSONKeys
mkObject.addJSONKeys( 'b', 'c' );

Здесь следует важное правило: если вы не уверены наверняка, какие свойства должны попадать в результат работы функции .toJSON, всегда используйте .jset вместо обычного присваивания. Если ключи известны, то, лично я, предпочитаю всегда задавать данные по умолчанию:
var MyClass = Class({
	'extends': MK.Object,
	constructor: function( data ) {
		this
			.initMK()
			.jset({ // данные по умолчанию
				a: 1,
				b: 2,
				c: 3
			})
			.set( data ) // кастомные данные (data - обычный объект с данными)
		;
	}
});

Обратите внимание на вызов .initMK. Здесь он инициализирует не только объекты событий и «специальных» свойств, но и объект-множество ключей. Кроме этого, он добавляет необходимые обработчики событий вызывая событие "modify" при изменении данных. Пример:
var mkObject = new MK.Object();
mkObject.jset({
	a: 1,
	b: 2
});
mkObject.c = 3;

mkObject.on( 'modify', function() {
	alert( 'Data is changed' );
});

mkObject.a = 4; // вызывает обработчик
mkObject.b = 5; // вызывает обработчик
mkObject.c = 6; // обработчик не вызывается, так как ключ "c" не обозначен, как данные

Если передать классу аргумент в виде объекта, он интерпретирует его, как данные:
var mkObject = new MK.Object({ a: 1, b: 2 });
// то же самое, что и
var mkObject = new MK.Object();
mkObject.jset({ a: 1, b: 2 });

Перебрать данные можно с помощью метода .each:
var mkObject = new MK.Object();
mkObject.jset({
	a: 1,
	b: 2
});
mkObject.c = 3;
mkObject.each( function( item, key ) {
	console.log( key );
}); // выведет 'a', 'b'

Дока: finom.github.io/matreshka/docs/Matreshka.Object.html#each

Проверить, есть ли в объекте какое-нибудь свойство можно с помощью метода .hasOwnProperty
var mkObject = new MK.Object();
mkObject.jset( 'a', 1 );
mkObject.b = 2;
alert( mkObject.hasOwnProperty( 'a' ) ); // true
alert( mkObject.hasOwnProperty( 'b' ) ); // false ('b' не является данными)

Это позволяет юзать конструкцию for..in, как для обычного объекта:
for( var i in mk ) if( mk.hasOwnProperty( i ) ) {
	doSomething(i, mk[i])
}

UPD: Не работает в восьмом осле из-за ограничений Object.defineProperty

Есть еще ряд методов, имена которых говорят сами за себя:
.keyOf, который ищет ключ по значению и возвращает ключ (аналог .indexOf для массива).
.keys, возвращающий массив ключей.
.removeJSONKeys, удаляющий ключи из множества ключей, отвечающих за данные.

Взгляните на измененный пример из предыдущей статьи: jsbin.com/disigiza/1/edit
В конструкторе мы задаём данные по умолчанию:
	...
	constructor: function () {
		this
			.initMK()
			.jset({ // вот здесь
				userName: '',
				password: '',
				rememberMe: true
			})
			.bindings()
			.events();
	},
	...

А затем, вместо того, чтоб вручную конструировать объект, который должен быть послан на сервер, мы вызываем метод .toJSON:
	...
	login: function () {
		if (this.isValid) {
			alert( JSON.stringify( this.toJSON() ) );
		}
		return this;
	}
	...


В завершение


Теперь мы знаем, как отделить данные Матрешки от состояний, которые не интересны бекенду. Замечательно. Но что, если нам нужно множество данных? Что-то типа массива или коллекции из Backbone.js. Решение — класс MK.Array, о котором я расскажу в следующей статье.

Спасибо, что прочли статью до конца. Всем добра и хорошего кодинга.
  • +21
  • 3,7k
  • 7
Matreshka.js
34,00
JavaScript фреймворк
Поделиться публикацией

Похожие публикации

Комментарии 7

    +1
    Пожелание: избавиться от зависимости jQuery.
      +1
      Уже добавил в план.
        +1
        Тут, конечно, палка о двух концах. Если переписать таким образом библиотеку, то, скорее всего, ее размер вырастет. Для сайтов/приложений где все равно используется jQuery (а их большинство) это даст только бесполезное увеличение объема. Но с другой стороны, конечно, позволит не подключать увесистую библиотеку там, где это не требуется.

        Оптимальным было бы сделать некую jqLite (как в Angular, кажется), где реализовать только ту часть функционала, которая используется матрешкой. Тогда ее можно было бы использовать в тех приложениях, где нет необходимости во всей jQuery и дало бы экономию по объему кода. Но это требует больше усилий автора на разработку, а он мог бы потратить их на улучшения непосредственно самой матрешки.

        С третьей стороны, сейчас на сайте jQuery можно самому собрать лайт-версию. Возможно, это самый компромиссный вариант. Только тогда автору в документации надо указать, что конкретно используется.
          0
          Насколько я понял, данная библиотека является вариацией на тему data binging. Вопрос у меня возник такой: если библиотека для работы с данными, тогда зачем зависимость от утилиты предназначенной преимущественно для работы с DOM?

          Пример: проект на Sencha Touch / Ext.Js либо на любом другом фреймверке, где уже есть поддержка утилитарной библиотеки для работы с DOM, наличие еще одной утилитарной библиотеки для работы с DOM не допустимо. Другая ситуация: серверный JS — как быть, если хочешь использовать бибилиотеку, где наличие jQuery будет выглядеть странно?

          Вот почему хотелось бы, чтобы библиотека выполняла исключительно функцию датабиндинга, а работа с элементами DOM была вынесена как, например, плагин.
            0
            ну, тащем-та, согласен, так было бы лучше всего. Я просто попытался привести контраргументы для всех подходов.
        0
        Очень заинтересовала Ваша библиотека.

        Метод set полезная штука, но есть варианты, когда имена внутри класса не совпадают с именами пришедшими с сервера. Чтобы избежать рассуждений из серии: «нужно делать единообразие имен на клиенте и сервере» рассмотрим пример, когда одно приложение работает с API разных систем.

        Из выше сказанного возникает вопрос, планируется ли реализация mapping'а?
        Было бы очень удобно.

        PS Спасибо за библиотеку, надеюсь удастся её эффективно применить в проекте.
        Кстати, что с лицензией на использование?
          0
          Спасибо за отзыв :)
          Нет, реализации маппинга не планируется, хотя вы можете реализовать его самостоятельно (Матрешка легко расширяема).
          Лицензия MIT: полностью свободная, без ограничений на коммерческое использование.

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

        Самое читаемое