(Архив) Matreshka.js — Введение

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

Приветствую всех читателей и писателей хабра.

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


Код для привлечения внимания:
mk.on( 'change:x', function() {
	alert( 'x is changed to ' + this.x );
});
mk.x = 2; // alerts "x is changed to 2"

И это работает в… IE8.

Что такое Матрешка?

Матрешка, как фреймворк
Компактный размер и легкая в изучении архитектура даёт возможность строить крупные расширяемые приложения. Этим сегодня никого не удивишь, но я постараюсь.
Матрешка, как библиотека
Если фичи, предоставляемые Матрешкой вам понравятся, то не обязательно менять свой код. Матрешкой можно пользоваться, как набором классов с интересными методами.
Матрешка, как платформа для создания собственного фреймворка
Матрешка — расширяемый фреймворк общего назначения, который не позиционируется, как MVC, MVVM или %your_design_pattern% фреймворк, поэтому программист имеет возможность реализовать собственную архитектуру, которая будет уметь желаемый набор шаблонов проектирования.

Зачем?

Мне часом надоело думать о представлении и о том, чтоб его менять написанным мной кодом. Все костыли синхронизации данных и представления в Javascript вызывают у меня негативные чувства, и амбициозной, направленной в будущее, целью Матрешки является возможность полностью забыть о том, что у нас есть UI, оперируя только данными. Конечно же, решить эту задачу невозможно на 100%, но мы, программисты, должны выжимать максимум из данных нам инструментам, дабы сделать код чище, короче и гибче. Пора встряхнуть свой код и стать злым.
Гифка для привлечения внимания


Привязка данных


Известно, что, клиентские приложения в браузере требуют синхронизации между данными и представлением. Классическая задача: есть данные:
var o = { x: 2 };

Есть select, который должен менять эти данные:
<select>
	<option>1</option>
	<option>2</option>
	<option>3</option>
<select>

Если использовать чистый JS + jQuery код мы напишем примерно следующее:
$( 'select' ).on( 'change', function() {
	o.x = +this.value;
});

Затем, когда хотим поменять данные, пишем:
o.x = 1;
$( 'select' ).val( o.x );

Это не очень хорошо, так как заставляет устанавливать значение сразу для двух «атомов»: свойства и элемента.

Эту проблему решают по разному: Backbone (MVC) разделяет приложение на модель (Model, Collection), представление (HTML код) и контроллер (View). Knockout и Angular (MVVM) привязывают данные, используя практику, перекочевавшую из .NET в клиентский веб: часть логики, заменяющая контроллер (в данном случае ViewModel) пишется в HTML коде (прошу прощения, если описание неверно). Есть еще куча фреймворков, за которыми не угонишься.

Матрешка привязывает данные к представлению таким образом, что, во первых, программист не трогает HTML код (в отличие от MVVM), во вторых, программист перестаёт думать о событиях HTML элемента для изменения модели (в отличие от Backbone).
var mk = new Matreshka; // или new MK; помните, что MK === Matreshka, это обычное сокращение
mk.bindNode( 'x', 'select', {
	on: 'change',
	getValue: function() {
		return this.value;
	},
	setValue: function( v ) {
		this.value = v;
	}
});

Если мы хотим поменять данные, то просто пишем:
mk.x = 2;

Такой код не только присвоит иксу двойку, но и поменяет состояние селекта, установив ему .value = 2.
И это без использования методов, типа .set.
jsbin.com/jikewipi/2/edit

Что здесь произошло?
mk.bindNode( 'x', 'select' ... )

Метод bindNode, как ни странно, отвечает за привязку элемента к свойству. Первый аргумент — ключ объекта, второй — селектор, в данном случае 'select'. Тип второго аргумента — любое значение, которое принимается jQuery: селектор, чистый элемент, jQuery объект, NodeList, массив элементов… То есть, 'select' можно заменить на $( 'select' ) или document.getElementsByTagName( 'select' ) или document.querySelector( 'select' ).

Третий аргумент — самое интересное, разберем по порядку.
on: 'change' 
Отвечает на вопрос: «Какое событие должно произойти на элементе, чтобы мы взяли значение из элемента и присвоили соответствующему свойству?»

getValue: function() {
	return this.value;
}
Отвечает на вопрос: «Каким образом извлечь значение элемента?», возвращая значение.

setValue: function( v ) {
	this.value = v;
}
Отвечает на вопрос: «Как нам установить значение для элемента?», где v — значение (в данном случае, 2).

Ссылка на доку: finom.github.io/matreshka/docs/Matreshka.html#bindElement

Усложним задачу. Скажем, у нас есть слайдер из jQuery UI: api.jqueryui.com/slider и у нас появилась задача привязать его к нашим данным. Смотрим документацию и видим событие "slide", которое срабатывает при перетаскивании ползунка.

Во-первых, перед привязкой объявим слайдер:
<div class="slider"></div>

$( ".slider" ).slider({ min: 0, max: 100 });

Во-вторых объявляем экземпляр Матрешки:
var mk = new Matreshka();

Дальше вызываем привязку:
mk.bindNode( 'x', '.slider', {
  on: 'slide', // событие, по которому из элемента извлекается значение
  getValue: function() {
    return $( this ).slider( 'option', 'value' ); // как вытащить значение из элемента (см. документацию jQuery ui.slider)? 
  },
  setValue: function( v ) {
    $( this ).slider( 'option', 'value', v ); // как установить значение для элемента (см. документацию jQuery ui.slider)? 
  }
});

Теперь, когда мы вызовем следующий код…
mk.x = 44;
… позиция слайдера изменится.

И наоборот, когда мы перетащим ручку слайдера, наш mk.x изменится.

UPD: Начиная с версии 0.2, третий аргумент имеет новый ключ 'initialize', который позволяет проинициализировать элемент перед его привязкой. См. статью о 0.2. Код теперь выглядит так:
mk.bindNode( 'x', '.slider', {
  initialize: function() {
    $( this ).slider({ min: 0, max: 100 });
  },
  on: 'slide',
  getValue: function() {
    return $( this ).slider( 'option', 'value' );
  },
  setValue: function( v ) {
    $( this ).slider( 'option', 'value', v );
  }
});


Еще немного усложним задачу, добавив HTML элемент, выводящий значение:
<div class="output">Value is <span class="x"></span></div>

И привяжем его к 'x':
mk.bindNode( 'x', '.output .x', {
  setValue: function( v ) {
    this.innerHTML = v;
  }
});

Как видно, у опций привязки элемента отсутствует свойство "on" и метод "getValue". Это значит, что из элемента ".output .x" мы не будем извлекать значение, а только устанавливать.

Мы можем привязать к одному свойству несколько элементов. Обратное утверждение тоже верно: мы можем привязывать к одному элементу много свойств. Просто помните, что Матрешка умеет привязывать элементы по правилу «многие ко многим».

Результат: jsbin.com/bulobuhu/7/edit (откройте вкладку Console и попробуйте изменить x, например, напишите mk.x = 42;)

Отлично, мы привязали два элемента, но получили кучу избыточного кода (на мой взляд). Что, если у нас будет много слайдеров? Каждый раз писать…
mk.bindNode( property, element, {
  on: 'slide',
  getValue: function() {
    return $( this ).slider( 'option', 'value' );
  },
  setValue: function( v ) {
    $( this ).slider( 'option', 'value', v );
  }
});
… не очень красиво.

Что делать? Надо запомнить общие черты элементов, которые будут проверяться при привязке элементов. Было бы удобно сделать так:
mk.bindNode( 'x', '.slider' );

Как это сделать? У Матрешки есть статичное свойство MK.elementProcessors MK.defaultBinders (переименовано), которое является массивом функций. Функции принимают аргумент el, являющийся проверяемым элементом, и содержат условие: если элемент соответствует некоторому правилу, то возвращаем объект опций, которые в примерах .bindNode выше, являются третьим аргументом.

Для любого слайдера есть одно правило: каждый имеет класс ui-slider. Поэтому наша функция-условие будет выглядеть так (UPD: не забудьте, о свойстве 'initialize'):
function( el ) {
  if( $( el ).hasClass( 'ui-slider' ) ) {
    return {
      on: 'slide',
      getValue: function() {
        return $( this ).slider( 'option', 'value' );
      },
      setValue: function( v ) {
        $( this ).slider( 'option', 'value', v );
      }
    };
  }
}

Пример, надеюсь, достаточно прост: мы проверяем, является ли элемент слайдером и, если да, возвращаем опции.

Вставляем функцию в массив MK.defaultBinders:
MK.elementProcessors.push( function( el ) {
  if( $( el ).hasClass( 'ui-slider' ) ) {
    return {
      on: 'slide',
      getValue: function() {
        return $( this ).slider( 'option', 'value' );
      },
      setValue: function( v ) {
        $( this ).slider( 'option', 'value', v );
      }
    };
  }
});


Ссылка на доку: finom.github.io/matreshka/docs/Matreshka.html#defaultBinders

После этого, имея хоть сотню слайдеров, в функции .bindNode мы определяем только лишь свойство и привязываемый элемент:
<div class="slider1"></div>
<div class="slider2"></div>

$( ".slider1, .slider2" ).slider({ min: 0, max: 100 });
var mk = new Matreshka();
mk.bindNode({
  x1: '.slider1',
  x2: '.slider2'
});

Результат: jsbin.com/celarefu/2/edit

Обратите внимание на то, как в примере по ссылке привязан вывод:
mk.bindNode({
  x1: '.output .x1',
  x2: '.output .x2'
}, MK.binders.innerHTML() );

MK.binders — статичное свойство, содержащее кастомные функции-привязчики, которые должны возвращать объект описанный выше (со свойствами on, setValue, getValue). Объект можно расширять собственными биндерами.
MK.binders.innerHTML — функция, возвращающая опции привязки к обычному html элементу, меняя его innerHTML.

Дока: finom.github.io/matreshka/docs/Matreshka.binders.html#innerHTML

Почему бы не создать правило, которое меняет .innerHTML для любого элемента, не соответствующего ни одному другому правилу? Одним словом: удобство. Иногда есть нужда привязывать элементы, для которых не требуется установка значения, но об этом в следующей статье.

По умолчанию MK.defaultBinders содержит одну функцию, проверяющую элемент на соответствие тривиальным правилам, давая возможность использовать простые элементы (select, textarea, input[type="text"], input[type="checkbox"], input[type="radio"]).
Например,
<select class="my-select">
   ...
</select>

Используя такой код:
mk.bindNode( 'x', '.my-select' );
… Матрешка сама узнает, когда, как добыть, как установить значение элемента, так как используется самый обычный select.

Пример: jsbin.com/tepiyoso/2/edit (нажимайте, изменяйте текст инпутов и взгляните на исходник)

Крититка подхода с селектором по классу
Два дня назад я запостил анонс Матрешки на форум javascript.ru. Пользователь nerv_ обоснованно описал критику подхода с селекторами, приведя код на AngularJS.
Получается, нужно следить как минимум за служебными селекторами.
И получается что все «биндинги» необходимо писать в js коде. А их, как правило, много, вместо того, чтобы задать декларативно — дешево и сердито.

Я согласен, что при большом количестве привязываемых элементов нужно следить за тем, чтоб не изменить классы привязаных элементов, поэтому, в таком случае, возможно, подойдет указание ключей в UI:
<form>
	<select data-key="a"></select>
	<select data-key="b"></select>
</form>

Деревянный способ:
$( '[data-key]' ).each( function() {
	this.bindNode( this.getAttribute( 'data-key' ), this );
});

Правильный способ (подробнее о методе .each в статье об MK.Object):
this.each( function( v, key ) {
	this.bindNode( key, this.$( '[data-key=' + key + ']' ) );
});

Эти два способа можно назвать первыми шагами к паттерну MVVM, который можно реализовать на базе Матрешки. Готовится пруф в виде плагина и статьи о нем.

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



События


Матрешка содержит в себе генератор событий, который работает так же, как и в Backbone.js. Изначально, фреймворк писался под собственные нужды, поэтому часть кода, отвечающая за события, была позаимствована как раз из этого фреймворка. Но код этих методов оказался очень стабильным, поэтому было решено его оставить.
var mk = new Matreshka();
mk.on( 'someevent', function( a, b ) {
  alert( a + ', ' + b );
});
mk.trigger( 'Hello', 'World!' ); // alerts "Hello, World!"

Знакомо?

Ссылка на документацию: finom.github.io/matreshka/docs/Matreshka.html#on

Одной из вкусных возможностей, указанных в начале поста является отслеживание события изменения свойства:
var mk = new Matreshka();
mk.on( 'change:x', function() {
  alert( 'New x value is ' + this.x );
});
mk.x = 5; //alerts "New x value is 5"

Мы так же можем привязать свойство к какому-нибудь элементу и отслеживать изменение его значения:
<select class="my-select">
    <option>1</option>
    <option>2</option>
    <option>3</option>
</select>  

var mk = new Matreshka();
mk.bindNode( 'x', '.my-select' );
mk.on( 'change:x', function() {
  alert( 'x is now ' + this.x );
});

Здесь прослеживается огромная разница в подходах: раньше мы отслеживали изменения DOM элемента, а сейчас мы отслеживаем изменения данных, так как нам важны исплючительно данные, состояни элементов изменяются сами по себе.
Попробуйте сами: jsbin.com/dadakeba/1/edit

Использование метода .set


Метод .set просто присваивает значение заданному свойству. Он используется для двух целей:
1. Передача свойств в объект события change:*key* (например флага "silent"). UPD: Флагов стало больше.
mk.on( 'change:x', function( evtOpts ) {
  alert( evtOpts.myFlag );
});
mk.set( 'x', 5, { myFlag: 'blah' } ); // устанавливает свойство и вызывает событие "change:x"
mk.set( 'x', 42, { silent: true } ); // устанавливает свойство и не вызывает никаких событий
Обратите внимание, что даже если передан флаг silent: true, значение привязанного элемента всё равно изменится.
2. Сокращение кода. В метод .set можно передать объект со свойствами.
mk.set( { x1: 1, x2: 2 } );
mk.set( { x1: 3, x2: 4 }, { silent: true } );


Где взять?


Репозиторий на github: github.com/finom/matreshka (код фреймворка находится в папке build/)
Матрешка требует наличия jQuery, хотя планируется убрать зависимость от неё. Начиная с верссии 0.1, jQuery не требуется.

В завершение


Я познакомил вас с основными фишками, которые несет в себе Матрешка. Остальные функции вы можете найти в документации. Там же вы найдете другие, не менее важные методы:
.off, отключающий заданные события
.remove, удаляющий свойство
.define, навешивающий кастомные акцессоры
.defineGetter, навешивающий геттер на элемент
.bound, .boundAll, возвращающие элемент или коллекцию элементов, соответственно, привязанных к свойству
.unbindElement, разрывающий связь между свойством и элементом
… и другие.

Почему версия 0.0.X?

Просто потому, что проект, несмотря на то, что разрабатывается более года под другим именем, впервые представлен только сейчас (в этой статье).

Что дальше?

В следующей статье я расскажу, как написать своё первое приложение, используя Матрешку не просто как набор удобных функций, а как полноценный фреймворк, основанный на классах, и расскажу, почему именно классы (я знаком со здешним негодованием по поводу сего вопроса).
Дальше будет рассказано о классах MK.Array и MK.Object, отвечающих за данные.
После этого, если читателю интересно, я расскажу, как же работает магия, и как мне удалось реализовать поддержку Object.defineProperty в IE8.

Огромное спасибо всем, кто смог прочесть статью до конца. Желаю удачи и успешного кодинга.
Matreshka.js
24,00
JavaScript фреймворк
Поделиться публикацией

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

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

    +1
    Было бы интересно посмотреть матрешку со связыванием данных Angular.
      0
      Знаком с Angular (хотя и не использовал в крупных проектах), но не совсем понимаю, что вы имеете в виду.
        +7
        В angular уже есть инфраструктура для привязки данных. Применять там матрешку, это то же самое, что одновременно ехать верхом на двух лошадях. :)
          0
          За лошадьми это к Derby.js
            0
            В Derby матрешка тоже не нужна.
        +3
        Спасибо, очень интересно, поглядываю какое-то время на FRP/ClojureScript/Javelin, но руки как-то не доходят, а Матрешка вроде попроще)
          +2
          И снова зависимость от jquery :-/
            0
            Да, к сожалению. Но это пока.
              0
              Angular до сих пор не избавился
                +1
                Откуда в angular вдруг зависимость от jquery?
                Там есть встроенное средство JLite, если не ошибаюсь. JQuery подключается при необходимости, но зависимости от него нет.
                  0
                  JqLite, что сразу же намекает: Р
                    +1
                    Следуя вашей логике Java намекает на JavaScript? Ведь это не одно и тоже.
                      0
                      вы сами можете собрать jquery без ненужных модулей, и получить навыходе jqlite.
                    0
                    Возможно bubuq говорил про проекты на Angular.js, в которые зачастую необходимо подключать jQuery, например из-за того же Angular.UI.
                      0
                      Если angular найдет jquery, будет использоваться как раз она, а не jqlite. В противном случае angular возьмет jqlite.
                        0
                        Ну так это и понятно. Ни кто вам не запрещает использовать jquery, но подход angular очень сильно отличается от подхода jquery, и ее использование не особо приветствуется.
                        Даже такие проекты как Angular.UI постепенно уходят от нее, а UI.Bootstrap вообще без нее обходится.
                  0
                  Про Object.defineProperty в IE8 расскажите, пожалуйста. Очень интересно звучит
                    +1
                    Для «обычных» объектов в IE8 это реально только через статический VBScript-класс. Ограничение VBScript это то, что статический класс невозможно расширить новыми свойствами. Единственный способ без VBScript — это проверка по таймеру каждые ~10+ мс не изменилось ли значение.
                    А в данной библиотеки используется экземпляр host-класса XDomainRequest. Над хост-объектами Object.defineProperty в IE8 работает.
                    В общем, реальных геттеров/сеттеров для любых объектов в IE8 нету и не будет.
                      0
                      Ничто не мешает в ие создавать новый статический класс и подменять им тот что был. Так же скорее всего можно нанэстить прототипов и расширять через них.
                        0
                        > Ничто не мешает в ие создавать новый статический класс и подменять им тот что был.
                        Мешает ограниченность VBScript'а. Всё-таки VBScript-объекты и JS-объекты совсем разные. Я знаю о чем говорю, потому что много эксперементировал с этим.
                        > Можно нанэстить прототипов и расширять через них.
                        Я не понял эту фразу, если честно.
                        В IE8- host-объекты, VBScript-объекты и объекты JS нельзя смешивать — т.е. нельзя назначить прототипом JS-объекта VBScript-объект и наоборот.
                        Там конечно есть нюансы, но я очень долго изучал этот вопрос — все пути решения в результате приводят к мелким и неудобным ограничениям, из-за которых просто невозможно универсально использовать какое-либо решение. Например, если создавать экземпляр host-класса, то у него нельзя сменить некоторые встроенные свойства — самое распространённое из которых это «toString», а могут быть недоступны на запись (и на Object.defineProperty) и такие свойства как «length» и т.д.
                          0
                          Скажите, я тут наивно подумал что раз в IE8 defineProperty работает с DOM, значит можно использовать DOM объект как прокси и через него эмулировать геттеры-сеттеры. Но будучи не очень глупым парнем я понимаю что не все так просто иначе уже давно народ бы пользовался. Не подскажите, а то ж я наверно зазря время потрачу в поисках решения? :)
                            +1
                            В принципе, это работает, но есть нюанс:
                            1. DOM-объект нельзя назначить в качестве prototype JS-объекту
                            2. У DOM-объекта нельзя сменить prototype
                            3. У DOM-объекта нельзя установить некоторые свойства, например toString

                            Это же касается VB-объектов.

                            Короче, не юзабельно. Я очень долго экспериментировал.
                            Вот тут подробное обсуждение: github.com/kriskowal/es5-shim/issues/152
                              0
                              3. У DOM-объекта нельзя установить некоторые свойства, например toString
                              У XDomainRequst можно.
                      0
                      Есть решение под ие6. Делается через vbScript. Используется как минимум в dojotoolkit. То есть делается функция на вбскрипте, которой передаётся объект, свойство, которое хотим ловить и пара функций на гет\сет. Так как вбскрипт\жс имеют общий скоуп, то в ие можно звать одно из другого.
                      +2
                      Видит новый разработчик в команде строчку
                      mk.x = 44;
                      и гадает, будет что-то обновляться визуально в этой строчке или нет. А если да, то как найти обработчик?

                      Ещё проблемный момент:

                      mk.x = 44; mk.x = 44; .... mk.x = 44; ;

                      Обновлений в html будет много, а надо только одно, как этим управлять?
                        0
                        и гадает, будет что-то обновляться визуально в этой строчке или нет

                        Мне очень сложно подобрать грамотный ответ на этот вопрос, так как не понимаю, в чем тут проблема. Предложите, пожалуйста, какой-нибудь вариант решения.
                        А если да, то как найти обработчик?
                        Искать по bindElement
                        Ещё проблемный момент:

                        mk.x = 44; mk.x = 44;… mk.x = 44;;

                        Обновлений в html будет много, а надо только одно, как этим управлять?
                        Почему вы так решили? ДОМ изменяется только тогда, когда меняется значение свойства: github.com/finom/matreshka/blob/master/src/matreshka.js#L885
                          –1
                          Предложите, пожалуйста, какой-нибудь вариант решения.

                          Тут к сожалению нет решения, для js точно, в каком-нибудь TypeScript можно, а тут нет.

                          Искать по bindElement

                          Как-то нетривиально, а если ещё смешивать с какими-нибудь другими либами, вообще не представляю как люди будут ориентироваться в таком коде.

                          ДОМ изменяется только тогда, когда меняется значение свойства

                          Пример я не очень удачный привёл. Суть в том, что когда меняется много свойств у модели, нужно чтобы вьюха обновилась только один раз, как это сделать?
                            0
                            По хорошему надо давать работать с матрёшкой только вьюхам, получится один объект — модель, на его ченьжи вешается изменение объекта замэппленного на дом, хотя тогда весь смысл матрёшки думаю теряется.
                              0
                              Тут к сожалению нет решения, для js точно, в каком-нибудь TypeScript можно, а тут нет.
                              Приведите на TypeScript (он всё равно в JS компилируется)
                              Пример я не очень удачный привёл. Суть в том, что когда меняется много свойств у модели, нужно чтобы вьюха обновилась только один раз, как это сделать?
                              Она и будет обновляться один раз. По разу на каждую привязку.
                              Как-то нетривиально, а если ещё смешивать с какими-нибудь другими либами, вообще не представляю как люди будут ориентироваться в таком коде.
                              Приводите, пожалуйста, примеры. Хотя бы скажите, где, в каком фреймворке и какие библиотеки используются.
                          0
                          Спасибо, заинтресовали. На выходных буду изучать кодовую базу. Не нашел на github roadmap, по возможности хотелось бы поучавствовать в разработке. А насколько сильная зависимость от jquery? Где он используется кроме поиска по DOM?
                            0
                            Роадмап пока только у меня в голове, давайте попробую:
                            — Допилить метод .addDependence (метод, который прописывает зависимость одного свойства от других). Лично мне этого часто не хватает. События иногда избыточны, а геттер мне не нравится из-за того, что вычисление значения может быть ресурсоёмким.
                            var mk = new MK;
                            mk.addDependence( 'perimeter', 'a b', function() { return ( this.a + this.b ) * 2} );
                            mk.addDependence( 'a', 'perimeter b', function() { return this.perimeter/2 - this.b } );
                            mk.addDependence( 'b', 'perimeter a', function() { return this.perimeter/2 - this.a } );
                            

                            Здесь пример решения математической задачи, которая может зациклиться и убить окно, если формула не верна. Надо подумать, как избежать таких проблем.
                            — Реализовать возможность добавлять DOM события к привязанным элементам таким образом:
                            mk.on( 'click::myKey', f ); // dom_event::property
                            

                            — Убрать зависимость от jQuery
                            — Сделать плагин MVVM
                            — Поправить опечатки в документации, допилить верстку (это только я могу сделать)

                            Зависимость от jQuery в основном в привязках, но она там серьезная.
                            0
                            Универсальный watch, который работает в том числе в IE8.
                            Но лично я использую Object Watch и доволен. IE8 просто динамлю…
                              0
                              Так, стоп. Там же Object.defineProperty используется. Как это работает в IE8?
                              0
                              А где ссылка на TodoMVC?
                                0
                                finom.github.io/matreshka/todo/#/ вот здесь черновик todo.
                                  0
                                  Черновик потому что есть баги и код не до конца готов.
                                +1
                                а тесты производительности библиотеки при работе с большими и сложными формами или объемными UI проводились?
                                  0
                                  Если кратко, то нет. Но из опыта и ревизии кода могу утверждать, что код близок к оптимальному, кроме метода .unbindElement. Субъективная оценка скорости приложений со многими элементами — отлично. Я не заметил разницы между кодом с Матрешкой и без неё.
                                    0
                                    благодарю. Хотелось бы побольше примеров с Matreshka.Object, а то один пример это очень мало…
                                      0
                                      Скоро будет статья об MK.Object. Примеры на сайте со временем доработаю.
                                        +1
                                        А вот и она: habrahabr.ru/post/196886/
                                    0
                                    А можно как-то подключить файлы исходники из src и запустить?
                                      0
                                      Да, просто подключайте их в порядке:
                                      xclass.js (1)
                                      matreshka.js (2)
                                      object.mk.js (3 или 4)
                                      array.mk.js (3 или 4)
                                        0
                                        спасибо
                                          0
                                          У меня еще один вопрос, может я жутко туплю конечно, я разбирался с исходным кодом, но так и не пойму
                                          var mk = new MK();
                                          mk.on( 'change:x', function() {
                                              alert( 'x is changed to ' + this.x );
                                          });
                                          mk.x = 2;
                                          

                                          При выполнении последней строчки, что вызывается?
                                          bindElement не вызывается
                                            0
                                            Алерт x is changed to 2
                                              0
                                              нет, я имею ввиду, в matreshka.js что вызывается?
                                              что вызывает эту функцию мою?
                                              или это не в matreshka.js
                                                0
                                                Матрешка вызовет. Первое — создаете экземпляр Матрешки (MK и Matreshka — одно и то же), второе — навешиваете обработчик события изменения свойства x, третье — меняете x.
                                                … Если я правильно понял ваш вопрос.
                                                  0
                                                  Мне интересно именно что происходит после присвоения mk.x = 2;
                                                  какая функция матрешки срабатывает именно в этот момент
                                                  как срабатывает такой обработчи, мы просто изменили свойство объекта присвоип просто значение, не методом, а напрямую
                                                  как метрешка узнает, что это событие произошло?
                                                    0
                                                    Сработает сеттер (см. Object.defineProperty)
                                                      0
                                                      аа, спасибо большое
                                        0
                                        mk.x = 2;

                                        1. В «ангуларе» у меня есть объекты с данными (прилетают с сервера), атрибуты которых привязаны, и я просто присваиваю объект — все привязки работают, пример:
                                        mk.movie = { title:'die hard', year:1995 };
                                        mk.movie = movie2;
                                        mk.movie = movie3;
                                        

                                        Как быть с матрешкой?

                                        2. Как я понял, «привязки» срабатывают сразу после изменения значения — это не всегда хорошо, т.к. иногда придется учитывать порядок обновления переменных, плюс эти переменные не желательно использовать «повсеместно» т.к. они «тяжелые».
                                        Мне больше нравится подход ангулара — обновление происходит когда все переменные посчитаны, данные обновлены.

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

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