vue作为现在热门的三大框架之一,相信大部分前端开发者都能够熟练的使用vue,但是能够深入了解其原理的可能并不多,很多人都知道vue响应式是通过difineProperty来实现的,相信随便百度一下,相关的面试题及答案一大堆,你知道是通过defineProperty重写get,set方法实现的,可是你有真正的了解过吗?好了,上干货!!!
实现对象的监听
此时能够监听对象数据的变化,还不能监听数组的变化。为什么?因为它本身就不可以呀,那你可能要问了,明明vue的数组,,通过push、pop、shift等等方法改变数组是监听到变化的呀。没错,vue是可以监听到,那是因为重写了数组push、pop、unshift、shift等方法,别急,后面慢慢道来。
(在代码中我会写清楚注释,如果有不理解的地方、或者不对的地方,欢迎留言指出)
function observe(target) {
if (typeof target !== 'object' || target === null) {
return
}
for(let key in target) {
defineReactive(target, key, target[key])
}
}
function defineReactive(target, key, value) {
console.log(target, key, value)
Object.defineProperty(target, key, {
get (key) {
return value
},
set (newValue) {
if (value !== newValue) {
observe(value) // 新赋值的数据可能是对象,数组等,此处需要处理新的数据
const oldValue = value //对象无法知道旧的数据,因为是引用类型
value = newValue
updateData(value, oldValue)
}
}
})
}
function updateData(value, oldValue) {
// 监听到了数据变化,更新视图
console.log('监听到了数据变化,更新视图 => ', value, oldValue)
}
let obj1 = {
a: 111,
c: 'djklf',
d: {
d1: 123
},
// arr: ['122', 453, 'kk']
}
observe(obj1)
console.log(obj1.a)
obj1.a = 'ff'
监听数组的变化
这里涉及到一些原型链的知识点,不做讲解,如果有需要的话留言哦
const arrProperty = Array.prototype
const arrProto = Object.create(arrProperty)
// 此处只重写了push、pop、unshift、shift方法,
// vue支持的方法为:push、pop、shift、unshift、splice、sort、reverse
;['push', 'pop', 'unshift', 'shift'].forEach(methodName => {
arrProto[methodName] = function () {
arrProperty[methodName].call(this, ...arguments)
updateData('数组改变','数组改变') // 数据更新
}
})
当数据为数组是改变它的__proto__
if (target instanceof Arrary) {
target.__proto__ = arrProto
}
完整代码
const arrProperty = Array.prototype
const arrProto = Object.create(arrProperty);
['push', 'pop', 'unshift', 'shift'].forEach(methodName => {
arrProto[methodName] = function () {
arrProperty[methodName].call(this, ...arguments)
updateData(1,1) // 监听到数据更新
}
})
function observe(target) {
if (typeof target !== 'object' || target === null) {
return
}
if (target instanceof Array) {
target.__proto__ = arrProto
}
for(let key in target) {
defineReactive(target, key, target[key])
}
}
function defineReactive(target, key, value) {
observe(value)
Object.defineProperty(target, key, {
get () {
return value
},
set (newValue) {
if (value !== newValue) {
observe(value) // 新赋值的数据可能是对象,数组等,此处需要处理新的数据
const oldValue = value
value = newValue
updateData(value, oldValue)
}
}
})
}
function updateData(value, oldValue) {
// 监听到了数据变化,更新视图
console.log('监听到了数据变化,更新视图 => ', value, oldValue)
}
// 测试数据
let obj1 = {
a: 111,
c: 'djklf',
d: {
d1: 123
},
arr: ['122', 453, 'kk']
}
observe(obj1)
// 1秒后改变数据
setTimeout (() => {
obj1.a = '1111'
obj1.d.d1 = 'ff'
obj1.c = {
c1: 'fdf',
c2: 1324
}
obj1.c.c1 = 222
obj1.arr.push('ff')
console.log(obj1.arr)
}, 1000)
总结
通过上面相信已经懂了响应式原理的实现了吧,所以我们能得出以下结论:
- 在data里,不要把对象定义的太深,循环遍历data里的数据做处理是需要时间的!!!
- 不需要响应式的不要定义在data里!!!可以定义在created中
- 数组的响应只能通过上面重写过的几个方法