vue双向数据绑定原理

一、vue双向数据绑定原理

vue实现双向数据绑定是通过Object.defineProperty()方法来实现劫持的
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象
Object.defineProperty()方法解析
Object.defineProperty()方法有三个参数:
Object.defineProperty(obj, key, options)

参数 功能/作用
obj 要修改或定义key值的对象
key 对应obj对象的里面某有已有或要修改的属性
options 这个参数对象里面有get,set两个函数,用来定义属性值
options有两种主要形式:数据描述符和存取描述符
数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的
存取描述符是由getter-setter函数对描述的属性
描述符必须是这两种形式之一;不能同时是两者
options参数配置:
数据描述符和存取描述符均具有以下可选键值
{
    configurable: Boolean, // 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除,默认为 false
    enumerable: Boolean, // 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中

}

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

{
    value: undefined, // 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined
    writable: Boolean, // 当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为 false
}

存取描述符同时具有以下可选键值:默认值:undefined

{
    get: fn, // 一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象),这个方法没有参数
    set: fn, // 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法有一个参数,就是对应的每次修改的新值
}

二、模拟测试

let Test = {
    name: 1
}

console.log(Test.name) // 1

如果我现在想要让1,输出true,0输出false,怎么办?我们可以通过Object.defineProperty()方法实现

let Test = {}
  let name = ''
  Object.defineProperty(Test, 'name', {
    configurable: true,
    enumerable: true,
    set: function (val) {
      name = val
      console.log('你输入的值为:' + val)
    },
    get: function () {
      if (name === 1) {
        name = true
        console.log('获取值的时候触发!')
        return name
      } else if (name === 0) {
        name = false
        console.log('获取值的时候触发!')
        return name
      }
    }
  })

分别测试一下结果:

Test.name = 0  => // 当我们改变对象或者为对象添加一个属性时,触发了set函数:你输入的值为:0
console.log(Test.name) => // false
console.log(name) => // false

// 通过测试改变Test对象的属性,我们发现不仅Test对象里面改变了,而且name变量也改变了
name = 0 => // 我们发现,我们改变了name变量的值,但是并没有触发set函数,(可以理解为set只能触发对象参数里面的改变)
console.log(Test.name) => // false
console.log(name) => // false

// 通过测试改变了name变量的值,发现兵没有触发set函数,但是Test对象和name变量的值还是跟着改变了,只触发了get函数,相当于获取name值

PS:这里是补充的,上面的测试依旧可以试下,但是原理和结论并不是那样的,其实Object.defineProperty()方法可以理解为监听的就是Test这个对象的,name就是添加的或对象已有的一个属性,这就是为什么上面单独改变name属性,并没有触发set函数,当我们改变Test对象的name属性时,set获取新值,并将其重新赋值给name变量,并在get函数里返回,这样就可以实现动态改变Test的name属性值来保持Test.name===name,所以我们只能操作Test.name,如果要操作name,还是要赋值给Test.name,间接操作Texst.name,然后触发后续事件
这里结合vue的双向绑定只能在input,checkbox这些标签上使用,可以理解为这些标签的value的属性值就相当于我们测试的name属性,通过value可以时刻动态监听input等标签value值的变化,然后将这个新value值赋值给对象指定属性,然后就可以触发后续函数。

三、简单粗暴的双向绑定

<div id="demo"></div> // 这个是用来动态显示input标签里面的value值的
<input type="text" id="inp" /> // 通过监听input标签的value值,赋值给我们监听的对象属性
let Obj = {} => // 监听对象
  let demo = document.getElementById('demo') // 获取DOM
  let inp = document.getElementById('inp') // 获取DOM
  Object.defineProperty(Obj, 'text', {
    configurable: true,
    enumerable: true,
    set: function (val) {
      // 将Obj对象新改变的值赋值给input的value,然后页赋值给demo
      inp.value = val
      demo.innerHTML = val
      console.log('input里面输入了' + val)
    },
    get: function () {
       // 返回对象
      return Obj
    }
  })

测试结果:
无论是在input标签里面输入,还是改变Obj.text的值,两者都会同时改变
至此,vue双向数据绑定原理挖坑完毕。

posted @ 2019-04-14 20:58  不会代码的前端  阅读(3564)  评论(0编辑  收藏  举报