Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue双向绑定的实现原理 #9

Open
Ray1993 opened this issue Oct 20, 2017 · 0 comments
Open

Vue双向绑定的实现原理 #9

Ray1993 opened this issue Oct 20, 2017 · 0 comments

Comments

@Ray1993
Copy link
Owner

Ray1993 commented Oct 20, 2017

我们都知道Vue的核心是视图组件化和 数据驱动,本篇主要是对Vue的双向绑定原理的进行学习。

实现数据绑定的做法有大致如下几种:

  • 发布者-订阅者模式(backbone.js)

  • 脏值检查(angular.js)

  • 数据劫持(vue.js)

数据劫持: vue.js 采用数据劫持的方式,结合发布者-订阅者模式,通过 Object.defineProperty() 来劫持各个属性的setter,getter以监听属性的变动,在数据变动时发布消息给订阅者,触发相应的监听回调。

首先我们先来看看Object.defineProperty()怎么用:

语法:

Object.defineProperty(obj, prop, descriptor)

参数说明:

obj:必需。目标对象
prop:必需。需定义或修改的属性的名字
descriptor:必需。目标属性所拥有的特性

返回值:

传入函数的对象。即第一个参数obj

例子:

    var a= {}
    Object.defineProperty(a,"b",{
      value:123
    })
    console.log(a.b);//123

前两个参数不多说了,一看代码就懂,主要看第三个参数descriptor,看看有哪些取值

descriptor

  • value : 属性的值(不用多说了)
  • writable : 如果为false,属性的值就不能被重写,只能为只读了
  • enumerable : 是否能在for...in循环中遍历出来或在Object.keys中列举出来。
  • configurable : 总开关,一旦为false,就不能再设置他的(value,writable,configurable)
  • get : 一会细说
  • set 一会细说
    注意了,当我们只设置了value的值的时候,其他特性的值都默认为false,上面的代码例子可以理解为:
var a= {}
Object.defineProperty(a,"b",{
  value:123,
  writable:false,
  enumerable:false,
  configurable:false
})
console.log(a.b);//123

我们先具体来看看writable ,enumerable ,configurable

writable:
如果设置为fasle,就变成只读了。。

var a = {}; 
Object.defineProperty(a,"b", { 
    value : 123,
    writable : false });

console.log(a.b); // 打印 123
a.b = 25; // 没有错误抛出(在严格模式下会抛出,即使之前已经有相同的值)
console.log(a.b); // 打印 123, 赋值不起作用。

enumerable :
属性特性 enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。

var a= {}
Object.defineProperty(a,"b",{
  value:123,
  enumerable:true
})
console.log(Object.keys(a));// ["b"]
for(var attr in a){
   console.log(attr)// b
}

//改为false

var a= {}
Object.defineProperty(a,"b",{
  value:123,
  enumerable:false //注意咯这里改了
})
console.log(Object.keys(a));// []
for(var attr in a){
   console.log(attr)// undefined
}

configurable:
总开关,第一次设置 false 之后,,第二次什么设置也不行了,比如说

var a= {}
Object.defineProperty(a,"b",{
  configurable:false
})
Object.defineProperty(a,"b",{
  configurable:true
})
//error: Uncaught TypeError: Cannot redefine property: b

这里要注意一下,上面讲的默认值,如果第一次不设置它,会帮你设置为false,所以再设置他,也会报错哦。。。

现在来看看属性descriptor剩下的两个方法setget

注意:当使用了get或set方法,不允许使用writable和value这两个属性。get或set不是必须成对出现,任写其一就可以。

var obj = {};
var initValue = 'hello';
Object.defineProperty(obj,"newKey",{
    get:function (){
        //当获取值的时候触发的函数
        return initValue;    
    },
    set:function (value){
        //当设置值的时候触发的函数,设置的新值通过参数value拿到
        initValue = value;
    }
});
//获取值
console.log( obj.newKey );  //hello

//设置值
obj.newKey = 'change value';

console.log( obj.newKey ); //change value

所以当我们设置了value的时候 我们获取值的时候 是直接获取我们自己设置的value;当我们设置get方法的时候,获取值的操作,是直接调用get里面的方法。

看完了上面的内容 我们利用数据劫持的方式,结合发布者-订阅者模式来实现一个极简的MVVM:

<body>
  <input   type="text"   id="input_value"/>
  <p  id="p_value"></p> 
</body>
<script>
   let obj = { };
  Object.defineProperty(obj, "a" ,{
      set:(value) => {
             document.getElementById('input_value').value = value ;
             document.getElementById('p_value').innerHTML = value ;     
      } 
  })
  document.addEventListener("keyup",(e) => {
            obj.a = e.target.value ;
  })
</script>

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant