Matreshka.js — MK.Object

в 12:42, , рубрики: javascript, jquery, Matreshka, Matreshka.js, Веб-разработка, метки: ,

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

Класс, который нам в этом поможет, называется 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.bindElement( '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])
}

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

Взгляните на измененный пример из предыдущей статьи: jsbin.com/ATAPUCo/6/
В конструкторе мы задаём данные по умолчанию:

	...
	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, о котором я расскажу в следующей статье.

Спасибо, что прочли статью до конца. Всем добра и хорошего кодинга.

Автор: Finom

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js