声明本文不是教考点, 是通过代码, 一步步让你更明白是怎么实现的
Vue怎么实现响应式的
核心api defineProperty
基础版
// vue中的data
const data = {
name: 'xue',
age: 24
}
const updateView = () => {
console.log('更新了视图')
}
const definedReactive = (obj, key, value) => {
Object.defineProperty(obj, key, {
get: ()=>{
return value
},
set: val=>{
if(val !== value) {
value = val
updateView()
}
}
})
}
// 数据监听
const observe = (obj)=>{
if(typeof obj !== 'object' || obj === null) {
return obj
}
Object.keys(obj).forEach(key=>{
definedReactive(obj, key, obj[key])
})
}
observe(data)
data.age = 25 // 过年了得加一岁了
如何实现 深度监听
// vue中的data
const data = {
name: 'xue',
age: 24,
userInfo: {
name: 'xue ji hong',
company: 'mockuai'
}
}
const definedReactive = (obj, key, value) => {
observe(value)
Object.defineProperty(obj, key, {
get: ()=>{
return value
},
set: val=>{
if(val !== value) {
value = val
observe(val)
updateView()
}
}
})
}
data.userInfo.company = 'mockuai1'
data.userInfo = {name: 'xue', company: 'mockuai2'}
data.userInfo.company = 'mockuai3'
defineProperty:
- defineProperty 需要初始化一次性deep watch 所有的数据
- defineProperty 无法监听 属性的新增和删除 所以需要 Vue.set 和Vue.delete来补全
数组的监听
上面说到defineProperty无法做到监听数据的新增和删除, 那么数组的push pop等操作自然不会被监听到
然后我们需要重定义数组的方法
// vue中的data
const data = {
name: 'xue',
age: 24,
userInfo: {
name: 'xue ji hong',
company: 'mockuai'
},
word: ['你好']
}
// 重定义数组方法
const oldProperty = Array.prototype
const arrProto = Object.create(oldProperty);
['pop', 'push', 'unshift', 'shift'].forEach(name=>{
arrProto[name] = function(){
updateView()
return oldProperty[name].call(this, ...arguments)
}
})
// 数据监听
const observe = (obj)=>{
if(typeof obj !== 'object' || obj === null) {
return obj
}
if(Array.isArray(obj)){
obj.__proto__ = arrProto
}
Object.keys(obj).forEach(key=>{
definedReactive(obj, key, obj[key])
})
}
data.word.push('世界')