источник
Несколько дней назад я наблюдал за внедрением некоторых популярных мини -фреймворков MVVM (таких как более легкие рамки, такие как Avalon.js, Vue.js, а не более тяжелые рамки, такие как Angularjs и Emberjs). Популярные современные фреймворки MVVM, как правило, устраняют двунаправленное связывание данных (двустороннее привязка данных), которая является точкой продажи самой структуры (ember.js, по-видимому, не поддерживает двунаправленное связывание данных), а методы реализации двунаправленного связывания данных каждой структуры не очень согласованы. Например, Anguarjs использует грязную проверку внутри, в то время как сущность внутренней реализации avalon.js заключается в том, чтобы установить аксессуры свойств.
Мы не намерены обсуждать конкретную реализацию двунаправленного привязки данных каждой структурой здесь. Мы будем говорить только о нескольких общих методах реализации двунаправленного привязки данных на передней части и сосредоточиться на техническом выборе Avalon.js для реализации двунаправленного привязки данных.
Традиционная реализация двусторонней привязки данных
Во-первых, давайте поговорим о том, что является двунаправленным привязыванием данных. Проще говоря, это уровень контроллера структуры (слой контроллера здесь является общим термином, который можно понять как промежуточное программное обеспечение, которое управляет поведением представления и соединяет модельный слой) и слой отображения пользовательского интерфейса (просмотр) для установления двунаправленного канала данных. Когда один из этих двух слоев изменяется, другой слой автоматически внесет соответствующие изменения немедленно (или, кажется, будет немедленно).
Вообще говоря, чтобы реализовать эту двустороннюю связь связывания данных (процесс корреляции между уровнем контроллера и слоем дисплея), в настоящее время на переднем крае существует три способа.
1. Грязная проверка
2. Механизм наблюдения
3. инкапсулируйте доклад о свойстве
Грязная проверка
Мы говорим, что AngularJS (здесь относится конкретно к версии AngularJS 1.xx, которая не представляет версию AngularJs 2.xx)-это техническая реализация двусторонней привязки данных. Общий принцип состоит в том, что AngularJS будет поддерживать последовательность и поместить все атрибуты, которые необходимо контролировать в этой последовательности. Когда возникают определенные конкретные события (обратите внимание, что это не время, но запускается некоторыми специальными событиями), AngularJS будет вызывать метод $ Digest. Логика внутри этого метода состоит в том, чтобы пересечь всех наблюдателей, сравнить контролируемые атрибуты и сравнить, изменилось ли значение атрибута до и после вызова метода. Если он изменится, соответствующий обработчик будет вызван. В Интернете есть много статей, которые анализируют принцип реализации двустороннего связывания данных AngularJS, например, в этой статье, и так далее.
Недостатки этого метода очевидны. Проверка и обучение наблюдателей очень потребляет производительность, особенно когда количество мониторинга одной страницы достигает порядка.
Механизм наблюдения
У блоггера была перепечатанная и переведенная статья, изменение привязки данных, вызванное Object.Observe (), которое относится к использованию метода Object.Observe в Ecmascript7 для мониторинга и наблюдения объекта (или его свойств). Как только это изменится, соответствующий обработчик будет выполнен.
Это самый идеальный способ мониторинга изменений данных атрибутов в настоящее время. Нативная поддержка языка (браузер) не является чем -то лучшим, чем эта. Единственное сожаление заключается в том, что нынешняя широта поддержки недостаточно хороша и должна быть полностью повышена.
Аксессор свойства свойства инкапсуляции
Существует концепция магических методов в PHP, таких как методы __get () и __set () в PHP. В JavaScript есть аналогичная концепция, но она называется не волшебным методом, а на аксессу. Давайте посмотрим на образец кода.
var data = {name: "erik", getName: function () {return this.name;}, setName: function (name) {this.name = name;}};Из приведенного выше кода мы можем увидеть прыжок, например, методы getName () и setName () в данных. Мы можем просто рассматривать это как аксессу (или аксессуар) data.name.
Фактически, для приведенного выше кода, если он более строгий, ему не разрешено напрямую получать доступ к свойству Data.name. Все чтение и запись в Data.Name должно быть передано через методы data.getName () и data.setName (). Итак, представьте, что, как только свойство не разрешает прямое чтение и запись к нему, но должно быть прочитано и написано через аксессуар, тогда, конечно, я делаю некоторые дополнения, переписывая метод собственности, такой как мониторинг изменения стоимости свойства. Это принцип использования Property Accessors для выполнения двустороннего привязки данных.
Конечно, этот метод также имеет свои недостатки. Наиболее заметным является то, что каждый раз, когда добавляется мониторинг атрибутов, к этому атрибуту должен быть добавлен соответствующий метод доклада, в противном случае изменение этого атрибута не будет захвачено.
Object.DefineProperty Метод
Принцип внутренней структуры MVVM avalon.js Реализация данных двунаправленного привязки данных является аксессуаром по недвижимости. Но, конечно, это не будет таким оригинальным, как приведенный выше пример кода. Он использует метод стандартного объекта свойства. Метод DefineProperty, определенный в ECMASCRIPT 5.1 (ECMA-262). В ответ на внутренние рыночные условия некоторые не поддерживают Object.DefineProperty. Браузеры низкого уровня используют VBScript для идеальной совместимости, в отличие от других фреймворков MVVM, которые постепенно отказались от поддержки браузеров низкого уровня.
Давайте сначала определим метод Object.DefineProperty на MDN.
Метод Object.DefineProperty () определяет новое свойство непосредственно на объекте или изменяет существующее свойство на объекте и возвращает объект.
Значение ясно, и метод Object.DefineProperty обеспечивает прямой способ определения свойств объекта или изменения существующих свойств объекта. Прототип метода заключается в следующем:
Object.DefineProperty (OBJ, PROP, Descriptor)
в,
obj, объект, который будет изменен
Опора, с измененным именем атрибута
дескриптор, соответствующее описание атрибутов, которые будут изменены
Дескриптор требует передачи объекта, его значение по умолчанию следующее
/*** @{param} дескриптор*/{настраивается: false, перечисляется: false, записи: false, значение: null, set: undefined, get: undefined}настраивается, настраивается ли свойство. Настраиваемые значения включают в себя: можно ли удалить атрибут, независимо от того, можно ли изменить записи, перечисляемые и настраиваемые свойства атрибута.
перечисляется, является ли атрибут перечисленным. Значение перечисленного включает в себя: можно ли это пройти через ... в ... в методе или получении его с помощью метода object.keys ().
Записывается, может ли атрибут быть перезагруженным. Значение перезагруженного включает в себя: можно ли переназначить атрибут.
Значение, значение по умолчанию свойства.
Установить, переписывание свойства (пока, вот и все). Как только атрибут будет переназначен, этот метод автоматически вызывается.
Получить, читатель собственности (пока, вот и все). Как только свойство доступно и прочитано, этот метод автоматически вызывается.
Вот пример кода,
var o = {}; object.defineproperty (o, 'name', {value: 'erik'}); console.log (object.getownpropertydescriptor (o, 'name')); // Object {value: "erik", записи: false, перечисляемое: false, настраивается: false} object.defineproperty (o, 'age', {value: 26, настраивается: true, rhopable: true}); console.log (o.age); // 26o.age = 18; console.log (o.age); // 18. Потому что возрастная собственность - это перезагруженная консоль.log (object.keys (o)); // []. Ни имя, ни возрастное свойство не является перечисленным объектом. DefineProperty (O, 'sex', {value: 'Male', записываемое: false}); o.sex = 'fome'; // назначение здесь на самом деле неэффективная консоль.log (o.sex); // 'мужчина'; удалить O.sex; // Неверно, действие Удаления свойства также недействительноПосле приведенного выше примера при нормальных обстоятельствах использование Object.DefinePropert () относительно просто.
Тем не менее, есть еще одна вещь, которая требует дополнительного внимания. Когда метод object.defineproperty () устанавливает свойства, свойство не может объявить атрибуты доклада (установить и получить) и атрибуты записи или значения одновременно. Это означает, что если определенное свойство установлено с атрибутом для записи или значения, это свойство не может объявить Get и установить, и наоборот.
Потому что, когда object.defineproperty () объявляет свойство, более двух типов элементов управления доступа не допускаются для одного и того же свойства.
Пример кода,
var o = {}, myName = 'erik'; object.defineproperty (o, 'name', {value: myname, set: function (name) {myname = name;}, get: function () {return myName;}});Приведенный выше код, кажется, в порядке, но он сообщит об ошибке, когда она фактически будет выполнена, и ошибка будет сообщена следующим образом.
TypeError: недействительное свойство. Свойство не может быть как аксессов, так и для записи или иметь значение, #<object>
Поскольку атрибут имени здесь объявляет атрибут значения, атрибуты SET и GET одновременно, оба из которых предоставляют два элемента управления чтением и записи на атрибуте имени. Если функция значения не объявлена здесь, но функция записи должна быть объявлена, результат будет таким же, и будет сообщена ошибка.