这里的代码只是说明最好用this
const myData = {n:0}const vm = new Vue({data(){return {n:0}},template:`<div>{{n}}<button @click="add">+10</button></div>`,methods:{add(){this.n += 10 //最好用this.n,因为一般data数据都写在opitons中了//myData.n += 10}}}).$mount("#app")setTimeout(()=>{myData.n +=10console.log(myData) //本节课精髓})
什么是数据响应式
如果修改Vue的实例vm.n的值,UI就会自动响应。
先插入一些知识点
先讲一下ES6的新语法,getter和setter
getter
let obj2 = {姓:"高",名:"圆圆",//get表示后面只是一个属性,只是以函数形式来定义而已,是计算属性get 姓名(){return this.姓 + this.名;},age:18}//调用不需要加括号obj2.姓名
setter
let obj3 = {姓:"高",名:"圆圆",set 姓名(xxx){this.姓 = xxx[0]this.名 = xxx.slice(1)},age = 18}//给姓名设置值obj3.姓名 = "刘诗诗"
虽然可以对”姓名”进行读和写,但并不存在一个真正的姓名属性,只存在”get 姓名”和”set 姓名”
再学习一下Object.defineProperty
给obj3添加一个属性
var _xxx = 0 //这个声明,是用来放xxx的值的//注意,这里的xxx是不存在的属性Object.defineProperty(obj3,"xxx",{get(){return _xxx},set(value){_xxx = value}})
几个实验
需求一,用Object.defineProperty定义
let data0 = {n:0}//需求一,用Object.defineProperty定义let data1 = {}Object.defineProperty(data1,"n",{value: 0})console.log(`需求一:${data1.n}`)//总结:这傻逼语法把事情搞复杂了?非也,继续看
需求二,不能小于0,即data2.n = -1应该无效,但data2.n = 1有效
let data2 = {}data2._n = 0 //_n 用来偷偷存储n的值Object.defineProperty(data2,'n',{get(){return this._n},set(value){if(value < 0) returnthis._n = value}})console.log(`需求二:${data2.n}`)
需求三,使用代理
let data3 = proxy({data:{n:0}}) //括号里是匿名对象,无法访问function proxy({data}){ //解构赋值const obj = {}//这里的n,写死了,理论上应该遍历data的所有key,这里做了简化//因为我怕你们看不懂Object.defineProperty(obj,'n',{get(){return data.n},set(value){if(value < 0) returndata.n = value}})return obj}console.log(`需求三:${data3.n}`)data3.n = -1console.log(`需求三:${data3.n},设置为-1失败`)data3.n = 1console.log(`需求三:${data3.n},设置为1成功`)
需求四,绕过代理仍然能改
let myData = {n:0}let data4 = proxy({data:myData})console.log(`杠精:${data4.n}`)myData.n = -1console.log(`杠精:${data4.n},设置为-1失效了吗?`)//现在还不是可以改myData
需求五,就算用户擅自修改myData,也要拦截他
let myData5 = {n:0}let data5 = proxy2({data.myData5})function proxy2(data){let value = data.n //保存最开始的nObject.defineProperty(data,'n',{ //这里声明的n是虚拟属性,放到了data上,会覆盖初始的nget(){return value},set(newValue){if(newValue<0) returnvalue = newValue}})//就加了上面几句,这几句话会监听data,是监听的逻辑const obj = {}Object.defineProperty(obj,'n',{get(){return data.n},set(value){if(value < 0) returndata.n = value}})//这几句是代理的逻辑return obj //obj就是代理}console.log(`需求五:${data5.n}`)myData5.n = -1console.log(`需求五:${data5.n},设置为-1失效了`)myData5.n = 1console.log(`需求五:${data5.n},设置为1成功了`)
以上是任何时候都能监听数据的修改,原理等同于vue的内部源码。
小结:
Object.defineProperty
可以给对象添加属性value
可以给对象添加getter/setter
getter/setter用于对属性的读写进行监控
啥是代理(设计模式)
对myData对象的属性读写,全权由另一个对象vm负责 
那么vm就是myData的代理(类似房东租房)
比如myData.n不用,偏要用vm.n来操作myData.n
vm=new Vue({data:myData})
一、会让vm成为myData的代理(proxy)
二、会对myData的所有属性进行监控
为什么要监控,为了放置myData的属性变了,vm不知道
vm知道了又如何?知道了属性变了就可以调用render(data)呀!
UI=render(data)
资料来源:饥人谷
