Javascript实现双向数据绑定

近几年前端技术栈真是发展的太迅速了,从以前的针对dom操作的框架如jquery,ext.js等框架逐步过渡到当前的mvvm模式,让前端开发者将注意力从dom操作逐渐解脱出来,专注于逻辑的实现,很大程度提升了开发效率,mvvm模式的一个核心便是数据的双向绑定。

什么是双向绑定

双向绑定即View与Model相互关联,相互影响。一般情况下,我们通过Model数据取更新View, 那如果用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定。

mvvm

在浏览器中,当用户修改了表单的内容时,我们绑定的Model会自动更新:

mvvm

双向绑定原理

以Vue为例,Vue中的数据双向绑定主要是采用数据劫持结合发布者-订阅者模式的方式使用Object.defineProperty()来劫持每个属性的gettersetter,当数据在变化时发布消息给订阅者,触发相应的监听回调。

Object.defineProperty()

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

语法:

1
Object.defineProperty(obj, prop, descriptor)

参数:

  • obj: 要在其上定义属性的对象
  • prop: 要定义或修改的属性的名称
  • descriptor:将被定义或修改的属性描述符

返回值:

  • 被传递给函数的对象

属性描述符

对象里目前存在的属性描述符有两种主要形式:数据描述符存取描述符数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的。存取描述符是由getter-setter函数对描述的属性。描述符必须是这两种形式之一;不能同时是两者

数据描述符和存取描述符均具有以下可选键值(默认值是在使用Object.defineProperty()定义属性的情况下):

  • configurable

    当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。

  • enumerable

    当且仅当该属性的enumerabletrue时,该属性才能够出现在对象的枚举属性中。

数据描述符同时具有以下可选键值

  • value

    该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined

  • writable

    当且仅当该属性的writabletrue时,value才能被赋值运算符改变。

存取描述符同时具有以下可选键值

  • get

    一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象),默认为 undefined。

  • set

    一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值,默认为 undefined。

描述符可同时具有的键值

configurableenumerablevaluewritablegetset
数据描述符YesYesYesYesNoNo
存取描述符YesYesNoNoYesYes

如果一个描述符不具有value,writable,get 和 set 任意一个关键字,那么它将被认为是一个数据描述符。如果一个描述符同时有(value或writable)和(get或set)关键字,将会产生一个异常。

示例

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html>
<head>
<title>ES6测试</title>
<meta name="keywords" content="ES6测试">
<meta name="description" content="ES6测试">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta name="format-detection" content="telephone=no">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="applicable-device" content="mobile">
</head>
<body>
<div id="app">
<h3 id="showText"></h3>
<input type="text" name="text" id="text">
</div>
<script type="text/javascript">
var data = {};
Object.defineProperty(data, 'name', {
get:function() {

},
set:function(val) {
document.getElementById('showText').innerHTML = val;
document.getElementById("text").value = val;
}
});

document.getElementById("text").addEventListener('keyup', function(e){
data.name = e.target.value;
})

</script>
</body>
</html>

页面测试效果

mvvm

有用就打赏一下作者吧!