origen
Hace unos días, estaba viendo la implementación de algunos marcos populares de mini MVVM (como marcos más ligeros como Avalon.js, Vue.js, en lugar de marcos más pesados como Angularjs y Emberjs). Los marcos MVVM modernos populares generalmente eliminan la unión bidireccional de datos (enlace de datos de dos vías), que es un punto de venta del marco en sí (Ember.js parece no admitir la unión bidireccional de los datos). Y los métodos de implementación de la unión de datos bidireccionales de cada marco no son muy consistentes. Por ejemplo, Anguarjs utiliza la verificación sucia internamente, mientras que la esencia de la implementación interna de Avalon.js es establecer accesorios de propiedades.
No tenemos la intención de discutir la implementación específica de la unión de datos bidireccionales por cada marco aquí. Solo hablaremos sobre varios métodos comunes para implementar la unión de datos bidireccionales en el frente, y centrarnos en la selección técnica de Avalon.js para implementar la unión de datos bidireccionales.
La implementación convencional de la unión de datos bidireccionales
Primero, hablemos de lo que es el enlace de datos bidireccionales front-end. En pocas palabras, es la capa del controlador del marco (la capa del controlador aquí es un término general, que puede entenderse como el middleware que controla el comportamiento de la vista y conecta la capa del modelo) y la capa de visualización de la interfaz de usuario (capa de vista) para establecer un canal de datos bidireccional. Cuando cualquiera de estas dos capas cambia, la otra capa realizará automáticamente los cambios correspondientes de inmediato (o parecen ser inmediatamente).
En términos generales, para realizar esta relación de enlace de datos bidireccional (el proceso de correlación entre la capa del controlador y la capa de visualización), actualmente hay tres formas en el front-end.
1. Cheque sucio
2. Mecanismo de observación
3. Accesor de propiedad encapsulada
Cheque sucio
Decimos que AngularJS (aquí se refiere específicamente a la versión AngularJS 1.xx, que no representa la versión AngularJS 2.xx) es una implementación técnica de la unión de datos de dos vías. El principio general es que AngularJS mantendrá una secuencia y colocará todos los atributos que deben ser monitoreados en esta secuencia. Cuando ocurren ciertos eventos específicos (tenga en cuenta que esto no está cronometrado, sino que se desencadena por algunos eventos especiales), AngularJS llamará al método $ Digest. La lógica dentro de este método es atravesar a todos los observadores, comparar los atributos monitoreados y comparar si el valor del atributo ha cambiado antes y después de la llamada del método. Si cambia, se llamará al controlador correspondiente. Hay muchos artículos en Internet que analizan el principio de implementación del enlace de datos bidireccional de AngularJS, como este artículo, etc.
Las desventajas de este método son obvias. Traversar y entrenar a los observadores es muy consumidor de rendimiento, especialmente cuando el número de monitoreo de una sola página alcanza un orden de magnitud.
Mecanismo de observación
El blogger tenía un artículo reimpreso y traducido, el cambio de enlace de datos provocado por Object.observe (), que se refiere a usar el método Object.observe en ECMAScript7 para monitorear y observar el objeto (o sus propiedades). Una vez que cambie, se ejecutará el controlador correspondiente.
Esta es la forma más perfecta de monitorear los cambios de datos de atributos en la actualidad. El soporte nativo del idioma (navegador) no es nada mejor que esto. El único arrepentimiento es que la amplitud actual de soporte no es lo suficientemente buena y necesita ser completamente promovida.
Accesor de propiedad de encapsulación
Existe un concepto de métodos mágicos en PHP, como los métodos __get () y __set () en PHP. Hay un concepto similar en JavaScript, pero no se llama un método mágico, sino un accesor. Veamos un código de muestra.
var data = {name: "erik", getName: function () {return this.name;}, setName: function (name) {this.name = name;}};Desde el código anterior, podemos ver el salto, como los métodos getName () y setName () en los datos. Simplemente podemos considerarlo como el accesor (o un accesor) de data.name.
De hecho, para el código anterior, si es más estricto, no se le permite acceder directamente a la propiedad Data.name. Toda la lectura y escritura a data.name debe pasar a través de los métodos data.getName () y data.setName (). Entonces, imagine que una vez que una propiedad no permita la lectura y la escritura directa, sino que debe leerse y escribir a través del accesor, por supuesto, hago algunos extras reescribiendo el método del accesor de la propiedad, como el monitoreo del cambio de valor de la propiedad. Este es el principio de utilizar los accesorios de propiedades para hacer un enlace de datos bidireccionales.
Por supuesto, este método también tiene sus inconvenientes. Lo más destacado es que cada vez que se agrega un monitoreo de atributos, se debe agregar un método de accesores correspondiente a este atributo, de lo contrario, el cambio de este atributo no se capturará.
Object.DefineProperty Method
El principio del marco MVVM nacional avalon.js que implementa la vinculación bidireccional de datos es el accesor de propiedad. Pero, por supuesto, no será tan original como el código de ejemplo anterior. Utiliza el objeto de propiedad estándar. DefineProperty Method definido en ECMAScript 5.1 (ECMA-262). En respuesta a las condiciones del mercado interno, algunos no admiten objetos. Defineproperty. Los navegadores de bajo nivel usan VBScript para una compatibilidad perfecta, a diferencia de otros marcos MVVM que han abandonado gradualmente el soporte para navegadores de gama baja.
Primero definamos el objeto. DefineProperty Method en MDN.
El método object.defineProperty () define una nueva propiedad directamente en un objeto, o modifica una propiedad existente en un objeto y devuelve el objeto.
El significado es claro, y el método Object.DefineProperty proporciona una forma directa de definir las propiedades de los objetos o modificar las propiedades de objetos existentes. El prototipo del método es el siguiente:
Object.DefineProperty (OBJ, Prop, Descriptor)
en,
obj, objeto a ser modificado
Prop, con nombre de atributo modificado
Descriptor, la descripción relevante de los atributos a modificar
El descriptor requiere que se pase un objeto, su valor predeterminado es el siguiente
/*** @{param} descriptor*/{configurable: falso, enumerable: false, witable: false, valor: null, set: undefined, get: indefinido}configurable, si la propiedad es configurable. Los significados configurables incluyen: si el atributo se puede eliminar, si se pueden modificar las propiedades de escritura, enumerables y configurables del atributo.
Enumerable, si el atributo es enumerable. El significado de enumerable incluye: si se puede atravesar para ... en y si se puede obtener a través del método Object.Keys ().
Writable, si el atributo puede ser reescrito. El significado de reescritura incluye: si el atributo se puede reasignar.
valor, el valor predeterminado de la propiedad.
Establecer, un reescritor de propiedad (por ahora, eso es todo). Una vez que se reasigna el atributo, este método se llama automáticamente.
Obtenga el lector de la propiedad (por ahora, eso es todo). Una vez que se accede y lee la propiedad, se llama automáticamente a este método.
Aquí hay un código de muestra,
var o = {}; object.defineProperty (o, 'name', {valor: 'erik'}); console.log (object.getOwnPropertyDescriptor (o, 'name')); // objeto {valor: "erik", writable: false, enumerable: false, configurable: false} objeto.defineproperty (o, 'edad', {valor: 26, configurable: true, witable: true}); console.log (o.age); // 26o.age = 18; console.log (o.age); // 18. Porque la propiedad de edad es una consola regritable.log (objeto.keys (o)); // []. Ni el nombre ni la propiedad de la edad son un objeto enumerable. // La asignación aquí es en realidad console ineficaz.log (o.sex); // 'masculino'; eliminar o.sex; // falso, la acción de eliminación de propiedad también no es válidaDespués del ejemplo anterior, en circunstancias normales, el uso de object.definePropert () es relativamente simple.
Sin embargo, todavía hay una cosa que necesita atención adicional. Cuando el método object.defineProperty () establece las propiedades, la propiedad no puede declarar los atributos del accesor (establecer y get) y los atributos de escritura o valor al mismo tiempo. Significa que si una determinada propiedad se establece con un atributo de escritura o valor, entonces esta propiedad no puede declarar Get and Set, y viceversa.
Porque cuando Object.defineProperty () declara una propiedad, más de dos tipos de controles de acceso no están permitidos para la misma propiedad.
Código de muestra,
var o = {}, myname = 'erik'; object.defineProperty (o, 'name', {value: myName, set: function (name) {myName = name;}, get: function () {return myName;}});El código anterior parece estar bien, pero informará un error cuando realmente se ejecute, y el error se informará de la siguiente manera.
TypeError: propiedad no válida. Una propiedad no puede tener accesorios y ser escritos o tener un valor, #<ject>
Debido a que el atributo de nombre aquí declara el atributo de valor, el conjunto y obtenga atributos al mismo tiempo, los cuales proporcionan dos controles de lectura y escritura en el atributo de nombre. Si la función de valor no se declara aquí, pero se declara la función de escritura, el resultado será el mismo y se informará un error.