Using Object. defineProperty to implement simple js bidirectional binding _ javascript skills

Source: Internet
Author: User
This article describes how to use Object. defineProperty to implement simple js bidirectional binding. Origin

A few days ago, I was looking at the implementation of some popular mini mvvm frameworks (such as avron. js and vue. js, rather than those of Angularjs and Emberjs. The popular mvvm framework usually removes two-ways data binding as a selling point of the framework itself. js does not seem to support two-way data binding .), In addition, the implementation methods of two-way data binding for each framework are inconsistent. For example, Anguarjs uses a dirty check internally, while the internal implementation of avron. js is essentially setting the attribute accesser.

We do not plan to discuss the implementation of two-way data binding by each framework here. We will only talk about several common methods for two-way data binding at the front end, and focus on aveon. js Technology Selection for bidirectional data binding.

Common Implementation of bidirectional data binding

First, let's talk about the frontend two-way data binding. Simply put, it is the Controller layer of the Framework (here the Controller layer is a generic, can be understood as controlling view behavior and contacting the middleware of the model layer) and the UI display layer (view layer) create a two-way data channel. When either of the two layers changes, the other layer automatically changes immediately (or appears to be immediately.

In general, to implement this two-way data binding relationship (the association process between the Controller layer and the presentation layer), there will beThree methods,

1. Dirty check

2. observation mechanism

3. encapsulate the property accessors

Dirty check

Let's talk about Angularjs (this is especially about AngularJS 1. x. version x does not represent AngularJS 2. x. version x) the technical implementation of bidirectional data binding is dirty checks. The general principle is that Angularjs maintains a sequence internally and stores all the attributes to be monitored in this sequence, when a specific event occurs (note that it is not scheduled but triggered by some special events), Angularjs calls the $ digest Method, the internal logic of this method is to traverse all watcher, compare the monitored attributes, and check whether the attribute values have changed before and after the method call, then the corresponding handler is called. There are many articles on the Internet that analyze the implementation principles of Angularjs two-way data binding, such as this article and this article.

The disadvantage of this method is obvious. traversing the training watcher consumes a lot of performance, especially when the number of single-page monitoring reaches an order of magnitude.

Observation mechanism

The blogger previously published an article on translation, Object. the Data Binding revolution brought about by observe () is to use the Object in ECMAScript7. the observe method monitors and observes the object (or its attributes). Once the object changes, the corresponding handler is executed.

This is currently the most perfect way to monitor attribute data changes. The language (browser) native support is nothing better than this. The only pity is that the current support breadth is not enough, and it needs to be fully promoted.

Encapsulate attribute accessors

There is a magic method concept in php, such as the _ get () and _ set () methods in php. Similar concepts exist in javascript, but they are not magic methods, but accessors. Let's take a look at the sample code,

var data = {name: "erik",getName: function() {return this.name;},setName: function(name) {this.name = name;}};

From the code above, we can look at the leopard, such as the getName () and setName () methods in data. We can simply regard it as the data. name accesser (or accesser ).

In fact, if the code above is more strict, direct access to data is not allowed. name attribute, all pairs of data. the name must be read and written through data. getName () and data. setName () method. Therefore, if a property does not allow direct read/write, it must be read and written by the accessors, then, of course, I will do some extra work by overwriting the access method of the attribute, such as monitoring the change of the attribute value. The principle of using the attribute accessors for two-way data binding is here.

This method also has drawbacks. The most prominent thing is that each time you add an attribute monitoring, you must add the corresponding accessors for this attribute. Otherwise, changes to this attribute cannot be captured.

Object. defineProperty Method

The principle of realizing two-way data binding through the domestic mvvm framework aveon. js is the attribute accesser. However, it is certainly not as original as the sample code above. It uses the standard property Object. defineProperty method defined in ECMAScript5.1 (ECMA-262. For the domestic market, some low-level browsers that do not support Object. defineProperty Use VBScript for Perfect compatibility, unlike other mvvm frameworks that have gradually abandoned support for low-end browsers.

Let's first define the Object. defineProperty Method on MDN,

The Object. defineProperty () method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.

The Object. defineProperty method provides a direct way to define Object attributes or modify existing Object attributes. The method is prototype as follows,

Object.defineProperty(obj, prop, descriptor)

Where,

Obj: the object to be modified.
Prop, with the modified attribute name
Descriptor: description of the property to be modified
Descriptor requires an object to be passed in. The default value is as follows,

/*** @{param} descriptor*/{configurable: false,enumerable: false,writable: false,value: null,set: undefined,get: undefined}

Whether the property is configurable. Configurable meanings include: whether the attribute can be deleted, and whether the writable, enumerable, and retriable attributes of the attribute can be modified.

Enumerable: whether the attribute can be enumerated. The enumerated meanings include: whether to traverse through for... in and whether to obtain the attribute name through the Object. keys () method.

Writable, whether the attribute can be overwritten. The meaning of rewriting includes: whether attributes can be re-assigned.

Value, the default value of the property.

Set, the property rewriter (this is currently called ). This method is automatically called once the attribute is assigned again.

Get, the reader of the attribute (this is now called ). This method is automatically called once the attribute is accessed and read.

The following is a sample code,

Var o ={}; Object. defineProperty (o, 'name', {value: 'erik '}); console. log (Object. getOwnPropertyDescriptor (o, 'name'); // Object {value: "erik", writable: false, enumerable: false, retriable: false} Object. defineProperty (o, 'age', {value: 26, retriable: true, writable: true}); console. log (o. age); // 26o. age = 18; console. log (o. age); // 18. because the age attribute is a Rewritable console. log (Object. keys (o); // []. the name and age attributes are not enumerated objects. defineProperty (o, 'sex ', {value: 'male', writable: false}); o. sex = 'female '; // The assignment here is actually a console that does not work. log (o. sex); // 'male'; delete o. sex; // false, attribute deletion is also invalid

After the above example, the use of Object. definePropert () is relatively simple under normal circumstances.

However, when setting attributes in the Object. defineProperty () method, the attributes cannot declare the accessors (set and get) and writable or value Attributes at the same time. This means that if the writable or value attribute is set for an attribute, the get and set attributes cannot be declared, and vice versa.

Because when Object. defineProperty () declares an attribute, more than two types of access control are not allowed for the same attribute.

Sample Code,

var o = {},myName = 'erik';Object.defineProperty(o, 'name', {value: myName,set: function(name) {myName = name;},get: function() {return myName;}});

The above Code seems to have no problem, but an error will be reported during actual execution. The error is as follows,

TypeError: Invalid property. A property cannot both have accessors and be writable or have a value ,#

Because the name attribute declares both the value attribute and the set attribute and the get attribute, the two provide two types of read/write control over the name attribute. If the value attribute is not declared, but the writable attribute is declared, the result is the same and an error is returned.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.