get set



-
get可以给对象的虚拟属性
姓名赋值,具体赋啥值是由里面的代码决定的。用obj.姓名可以读取该值 -
set必须给虚拟属性
姓名一个值,然后对这个值做些啥。用obj.姓名 = 高圆圆 -
虚拟属性 不存在 不能在其他地方调用
-
用
Object.defineProperty给一个对象再定义完之后添加新属性 具体语法
Object.defineProperty(obj,'xxx',{
get(){
return 0
},
set(value){
value+=1
}
})
obj.xxx //0
obj.xxx = 3
//给obj对象一个虚拟属性xxx,get用来给这个虚拟属性xxx赋了个值0;set用来给虚拟属性xxx一个值,然后对这个值干了些啥。
Vue对data做了些啥

n的值就是0,不是{value:0}

- get给虚拟属性
n赋值为this._n。直接data2.n就可以拿到 - set要求必须给虚拟属性一个值,如果这个值小于0就没啥,大于0就把这个值给
this._n。使用data2.n = value
- 代理obj(data3)的n就是data的n;给代理obj的n一个大于0的值,才会把这个值给data的n。
- data3就是obj ,代理的n就是数据的n,
- 你永远无法接触到n
- 对data的n读写完全不用他自己,而是通过对obj的n读写来实现



- 监听mydata(data)中的n:先把data的n偷来当原始值,再从data中删掉n,再给data一个虚拟的n。这个虚拟属性n的值就是之前偷来的n的值,如果给虚拟属性n一个大于0的值就把该值给之前偷来的n值。这样data中的n有任何改变我们都知道看得见。只有满足我们的条件我们才会允许data中的n改变。
- 所以虽然刚开始myData5(data)被声明在前面了,但是只要一对他执行
proxy2函数,就把它的n偷来了,还把他在原来的位置删掉了,我们给还了它一个虚假的n,虚假的n被我们用get set监控着。它要是在外面想改变自己的虚假的n,必须经过我们的同意满足我们的条件才行。 - obj(data5)就是代理 ,obj(data5)的n就是data(mydata)的n

vm = new Vue({data: myData})
首先,会马上对myData的所有属性进行监控,也就是对myData进行改造
-
防止myData的属性在外面变了,vm不知道,知道属性变了就可以调用render(data)呀!
UI = render(data) -
做法: 先把myData的属性n偷来变成我的value,在他的原位置删掉,我给你再补偿一个虚假的n,这个虚假的n一直被我用get(value) set(value)控制,听我的话,你在外面修改n,其实是我给你的虚假的n,都被我控制了。
-
你对data的任何修改,我Vue必须知道,不然我怎么对数据去渲染
其次,会让vm成为改造后的myData的代理(proxy)
- 所以vm(中介)就是myData(房东)的代理,vm的n就是myData的(虚假的)n;对vm的n赋值,就相当于对myData的(虚假的)n赋值;完全不直接操作myData的你,而是操作vm的n
- 而且this就是vm。所以this.n === vm.n === myData.假n

Object.defineProperty
- 可以给对象添加属性value
- 可以给对象添加getter / setter
- getter / setter用于对属性的读写进行监控
啥是代理(设计模式)
- 对myData对象的属性读写,全权由另一个对象vm负责
- 那么vm就是myData的代理(类比房东租房)
- 比如myData.n不用,偏要用vm.n来操作myData.n
数据响应式
“响应式”,是指当数据改变后,Vue会通知到使用该数据的代码。例如,视图渲染中使用了数据,数据改变后,视图也会自动更新。
- options.data
- 会被Vue监听
- 会被Vue实例代理
- 每次对data的读写都会被Vue监控
- Vue会在data变化时更新UI(因为UI用到了data,data变UI也变)
定义
- 什么是响应式
我打你一拳,你会喊疼,那你就是响应式的。若一个物体能对外界的刺激做出反应,它就是响应式的。
- Vue的data是响应式
const vm = new Vue({data: {n: 0})
我如果修改vm.n(data.n this.n),那么因为视图是对数据的渲染,所以视图中的n(UI中的n)也会改变做出反应也就是响应。这就是数据响应式。
-
如何实现数据响应式 Vue 2通过
Object.defineProperty(和getset)实现对数据的监听从而实现数据响应式 -
题外话:响应式网页是啥?
- 如果我改变窗口大小,网页内容会做出响应,那就是响应式网页
- 比如这个网站
- 但是你要注意,用户没事不会拖动网页大小的
Vue的data有bug:如果数据中有新增加的内容,那该怎么去监听?
现象
监听数据的话,用Object.defineProperty(obj, 'n' ,.})的话,数据中必须要有真的n,才能监听&代理obj.(假的)n。
如果前端开发者比较水,没有给真的n怎么办,根本没有n的监听
示例一 让视图中出现一个没有被声明的数据n

- vue对于undefined或者null就不会显示

- Vue会给出一个警告:属性或者方法n没有定义在实例上,但是却被你在渲染时引用了
示例二:
- data中定义了obj,obj中有个a,所以obj和obj.a都被Vue监听&代理了(vm.obj==this.obj===myData.obj),对a变化了因为视图因为用了a所以也会改变
- 但是并没有声明obj中还有个b,所以没有对obj.b监听&代理。所以对obj.b赋值并且放在视图,视图根本没变化,Vue认为根本没这样的存在。

解决办法
- 方法一:那我把数据中每个key一次性都声明好,也就全部监听好了
obj{
a:0,
b:undefined
}
- 方法二:使用
Vue.set或者this. $set
setB(){
Vue.set(this.obj,'b',1)
//或者,多了个$是为了防止和data中万一有个set咋办
this.$set(this.obj,'b',1)
}
作用
①新增key
②自动创建代理和监听(如果没有创建过)
③触发UI更新(但并不会立刻更新)
数组解决办法

- 方法一:使用
Vue.set或者this. $set,新增key,但是不会创建监听和代理,会更新UI
示例1:数组的长度可以一直增加,下标就是key 你看,你没有办法提前把数组的key都声明出来 Vue也不能检测对你新增了下标 难道每次改数组都要用Vue.set或者this. $set
- 方法二:尤雨溪篡改了数组的API,见官网中「变异方法」章节,这7个API都会被Vue篡改,这7个新API会调用数组原来的API并且自动增加监听和代理,并更新UI

尤雨溪是如何篡改的:新增加一层原型,这层原型继承了数组原型,这层原型有七个API,这七个API都会调用之前的数组原型中对应的那个API,之后set该set的东西。
以push为例
class VueArray extends Array{ //新增加一层原型VueArray,继承以前的Array原型
push(...args){ //新原型的push方法
const oldLength = this.length // this就是当前数组
super.push(...args) //会调用上一层原型(原来数组)的push方法
console.log(' push ')
for(let i = oldLength; i<this.length; i++){ //把之前的下标和现在新的下标找出来,中间的不就是新增加的,那就set他们就行了。
Vue.set(this, i, this[i])
// key Vue
} } }
总结
- 数据的对象中想新增的key,Vue没有办法事先监听和代理,要使用set来新增key,创建监听和代理,更新UI。结论:数据的对象的话提前把属性都写出来,不要新增key
- 但数据的数组做不到「不新增keyJ,数组中新增的key,也可用set来新增key,但是不会创建监听和代理,会更新UI;还有一种方法就是尤玉溪篡改了7个API方便你对数组进行增删(改不用监听,查不用监听),这7个API会自动处理监听和代理,并更新UI。因此结论:数据的数组新增key最好通过7个API