一、定义
vue是通过Object.defineProperty()来实现双向数据绑定的,它作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性
Object.defineProperty(obj, prop, desc)
- obj 需要定义属性的当前对象
- prop 当前需要定义的属性名
- desc 属性描述符
二、描述符属性配置
一般通过为对象的属性赋值的情况下,对象的属性可以修改也可以删除,但是通过Object.defineProperty()定义属性,通过描述符的设置可以进行更精准的控制对象属性。
Object.defineProperty(obj:对象, prop:key, descriptor:属性和方法)let obj = {}Object.defineProperty(obj,'a',{configurable: true //是否允许删除enumerable:true //是否允许枚举value:undefined //就是value值writable:true //是否允许赋值get() {} //获取的return的值set(newVal) {} //修改的时候执行 newVal就是最新的值})
//区别在于单个截止和多个劫持Object.defineProperties(obj,{a:{get() {//需要return 否则会返回 undefinedreturn 1}set(newVal) {//newVal 是给属性 a 最新赋的值//可以执行函数、dom操作等一些方法}},b:{get() {}set() {}}})
三、数据读写
读数据,会触发 get,并且 get 内部需要返回数据,才能读取到数据
但是由于 Object.defineProperty 的缺陷,直接在 return 后面 返回 data.name,会进入死循环,所以需要通过一个全局变量进行管理
const data = {name: '张三',age: 14}let value = data.nameObject.defineProperty(data, 'name', {get() {console.log('读数据了')return value},set(val) {console.log('写数据了')}})console.log(data.name)
四、写数据
const data = {name: '张三',age: 14}let value = data.nameObject.defineProperty(data, 'name', {get() {console.log('读数据了')return value},set(val) {console.log('写数据了' + val)value = val}})console.log(data.name)data.name = '赵四'console.log(data.name)
// 打印结果读数据了张三写数据了赵四读数据了赵四
五、单层数据响应
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><metaname="viewport"content="width=device-width, initial-scale=1.0"/><title>Document</title></head><body><div><p id="name"></p><p id="age"></p></div><script>// 定义数据const data = {name: '张三',age: 19}// 同步视图的方法function setView() {document.getElementById('name').innerHTML = data.namedocument.getElementById('age').innerHTML = data.age}setView()// 利用循环对数据进行监听Object.keys(data).forEach(key => {// 利用外部数据进行数据的读写控制let getValue = data[key]Object.defineProperty(data, key, {// 读数据get() {return getValue},// 写数据set(val) {getValue = valsetView()}})})</script></body></html>
六、数据无法响应的情况
https://cn.vuejs.org/v2/guide/reactivity.html
