Using Object.defineproperty to implement simple JS bidirectional binding _javascript Technique

Source: Internet
Author: User

Origin

A few days ago, we looked at some popular mini MVVM frameworks (such as avalon.js, Vue.js, rather than ANGULARJS, emberjs this heavier framework). The modern popular MVVM framework typically takes data two-way binding (two-ways data binding) as a selling point for the framework itself (Ember.js does not seem to support bidirectional data binding. , and each framework bidirectional data binding implementations are inconsistent, such as anguarjs internal use of dirty checks, and the essence of avalon.js internal implementation is to set property accessors.

Here is not going to specifically discuss the concrete implementation of each framework for two-way data binding, only to say the front-end to achieve two-way data binding several common methods, and focus on avalon.js to achieve two-way data binding technology selection.

General implementation of bidirectional data binding

Let's start with the bidirectional data binding for the front end. Simply put, the controller layer of the framework (the controller layer here is a generic one that can be understood to control view behavior and contact the model layer middleware) and the UI presentation layer (view layer) to establish a two-way data channel. When either side of the two layers changes, the other layer will automatically make a corresponding change immediately (or seemingly immediately).

In general, this two-way data-binding relationship (the link between the controller layer and the presentation layer) can be implemented in three different ways at the front end.

1. Dirty Check

2. Observation mechanisms

3. Encapsulating Property Accessors

Dirty Check

We say Angularjs (here specifically Angularjs 1.x.x version, does not represent Angularjs 2. x.x version) The technology implementation of bidirectional data binding is dirty check, the general principle is that the ANGULARJS internally maintains a sequence that places all the attributes that need to be monitored in this sequence, and when certain events occur (note that this is not timed but triggered by special events), Angularjs calls the $digest method, the internal logic of this method is to traverse all watcher, compare the monitored properties, compare the property values before and after the method call, and call the corresponding handler if the change occurs. There are many articles on the Internet to analyze the principle of ANGULARJS data binding, such as this article, and so on.

The disadvantage of this approach is obvious, traversing rotation watcher is very consuming performance, especially when the number of single page monitoring reaches an order of magnitude.

Observation mechanism

Bo Master before a reprint of the translation of the article, Object.observe () brought about by the data binding change, that is, using the Object.observe method in ECMAScript7 to monitor the object (or its properties), once it changes, The corresponding handler will be executed.

This is the most perfect way to monitor property data changes, language (browser) native support, nothing is better than this. The only regret is that the current scope of support is not enough, to be fully promoted.

Encapsulating Property Accessors

There is a concept of magic in PHP such as the __get () and __set () methods in PHP. There are similar concepts in JavaScript, but they are called accessors instead of magic methods. 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 above code we can glimpse, such as the GetName () and SetName () methods in data, we can simply see it as a data.name accessor (or an accessor).

In fact, for the above code, more strictly speaking, do not allow direct access to the Data.name property, all Data.name read and write must pass the Data.getname () and Data.setname () method. So, imagine that once a property is not allowed to read and write directly to it, but must be read and write through the accessor, then of course I do some extra feeling by overriding the accessor method of the property, such as the change of attribute value. The principle of using property accessors to do data two-way binding is here.

This method of course also has drawbacks, the most prominent is that each add a property monitoring, you must add a corresponding accessor method for this attribute, otherwise this attribute changes can not be captured.

Object.defineproperty method

The principle that the domestic MVVM frame Avalon.js realizes the data bidirectional binding is the property accessor. But it's certainly not as primitive as the example code above. It uses the standard attributes Object.defineproperty method defined in ECMAScript5.1 (ECMA-262). For the domestic market, part of the Object.defineproperty low-level browsers are not supported by VBScript for perfect compatibility, unlike other MVVM framework has gradually abandoned the support of low-end browsers.

Let's start by MDN the definition of the Object.defineproperty method,

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

The Object.defineproperty method provides a straightforward way to define an object property or modify an existing object property. Its method prototype is as follows,

Object.defineproperty (obj, prop, descriptor)

which

Obj, objects to be modified
Prop, with modified property name
Descriptor, description of the property to be modified
Descriptor requires that an object be passed in, with the default value below,

/**
* @{param} Descriptor * *
configurable:false,
enumerable:false,
Writable:false,
Value:null,
set:undefined,
get:undefined
}

Configurable whether the property is configurable. Configurable implications include whether you can delete a property (delete), and whether you can modify the writable, enumerable, configurable properties of the property.

Enumerable whether the property can be enumerated. The implications of enumerable include: whether you can traverse through for...in to, and whether you can get the property name through the Object.keys () method.

Writable whether the property can be overridden. What can be overridden includes whether the property can be assigned a new value.

Value, the default value of the property.

Set, an override of the property (this is called). This method is invoked automatically once the property is assigned a value.

Get, the reader of the property (for the moment). This method is invoked automatically once the property is read.

Here's a sample code,

var o = {};
Object.defineproperty (o, ' name ', {
value: ' Erik '
});
Console.log (Object.getownpropertydescriptor (o, ' name ')); Object {value: "Erik", Writable:false, Enumerable:false, configurable:false}
object.defineproperty (o, ' age ', { c6/>value:26,
configurable:true,
writable:true
});
Console.log (O.age);
o.age =;
Console.log (O.age); 18. Because the Age property is an overridable
Console.log (Object.keys (o)), the. Name and age properties are not enumerable
Object.defineproperty (o, ' sex ', {
value: ' Male ',
writable:false
});
O.sex = ' female '; The assignment here is actually
Console.log (o.sex);//' Male ';
Delete O.sex; False, the action of the property deletion is also invalid

With the above example, Object.definepropert () is normally used fairly simply.

But there's one thing that needs extra attention. When the Object.defineproperty () method sets the property, the property cannot declare both the accessor properties (set and get) and the writable or Value property at the same time. This means that a property has the writable or value attribute set, and then the property cannot declare get and set, and vice versa.

Because Object.defineproperty () does not allow two or more access control for the same property when declaring a property.

Sample Code,

var o = {},
myname = ' Erik ';
Object.defineproperty (o, ' name ', {
value:myname,
set:function (name) {
myname = name;
}, get
: function () {return
myname;
}
});

The above code looks like there is no problem, but the actual execution will be an error, the following error,

Typeerror:invalid property. A property cannot both have accessors and is writable or have a value, #<object>

Because the Name property here declares both the value attribute and the set and get attributes, both provide read and write control over the Name property. If you do not declare the value attribute, but declare the writable attribute, the result is the same and the error will be the same.

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.