数据响应式,顾名思义,Vue会在数据改变时做出响应,更新页面、执行函数等等,这便是Vue的数据响应式。
Vue通过监听observe和代理proxy实现数据响应式。
代理proxy
// 需求:n 不能小于 0
// 即 data1.n = -1 应该无效,但 data1.n = 1 有效
let data1 = proxy({ data:{n:0} }) // 括号里是匿名对象,无法访问
function proxy({data}){
const obj = {}
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(value){
if(value<0)return //加上限制条件
data.n = value
}
})
return obj // obj 就是代理
}
// data1 就是 obj
console.log(`data1:${data1.n}`) //需求三:0
data1.n = -1
console.log(`data1:${data1.n},设置为 -1 失败`) //需求三:0,设置为 -1 失败
data1.n = 1
console.log(`data1:${data1.n},设置为 1 成功`) //需求三:1,设置为 1 成功
通过代理obj来操作数据,可以给数据加上一定的限制条件。
代理不会改变原有对象。(房东找个中介,中介并不会动房子里的东西)
监听observe
// 需求:n 不能小于 0
// 同时 myData.n = -1 无效,但 myData.n = 1 有效
let myData = {n:0}
let data2 = proxy2({ data:myData }) // 括号里是匿名对象,无法访问
function proxy2({data}){
let value = data.n
Object.defineProperty(data, 'n', {
get(){
return value
},
set(newValue){
if(newValue<0)return
value = newValue
}
})
// 就加了上面几句,这几句话会监听 data
const obj = {}
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(value){
if(value<0)return
data.n = value
}
})
return obj // obj 就是代理
}
// data2 就是 obj
console.log(`n:${data2.n}`) //n:0
myData.n = -1
console.log(`n:${data2.n},设置为 -1 失败了`) //n:0,设置为 -1 失败了
myData.n = 1
console.log(`n:${data2.n},设置为 1 成功了`) //n:1,设置为 1 成功了
通过监听,使得直接操作对象的n也能被察觉
监听会改变原有对象。(房东的房子会被中介装摄像头、窃听器,改变了房屋)
监听先将原对象的n保存了下来,然后用getter&setter替换了n的值。
Vue.set & this.$set
若对象新增了key,那么Vue可以通过Vue.set和this.$set为新key创建代理和监听
Vue.set(vm.someObject, 'b', 2)
//还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:
this.$set(this.someObject,'b',2)
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
对于数组
Vue使用了变更方法Mutation Methods
Vue 将被监听的数组的部分方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()pop()shift()unshift()splice()sort()reverse()
可以看到,进入Vue的数组的__proto__被Vue用变更方法替代了,原来关于Array的__proto__被放到了数组的原型的原型中。