vue2响应式原理:核心使用Object.defineProperty给属性定义get和set方法
注意:对象的多次递归,针对数组需要重写数组方法
函数劫持:把函数内部进行重写同时继续调用老的方法,在继承原数组方法时使用到
主要方法介绍:
updataView:模拟更新视图时触发的方法
observer:观察者
defineReactive:核心部分,get和set方法
//针对数组部分
let oldArrayPrototype = Array.prototype;
//继承旧数组的方法
let proto = Object.create(oldArrayPrototype)
//js省略;写法注意在括号前面加分号
;['push','shift','unshift'].forEach(method=>{
//函数劫持
proto[method] = function(){
updateView()
oldArrayPrototype[method].call(this,...arguments)
}
})
function observer(target){
//基本数据类型不需要处理,直接返回
if(typeof target !== 'object' || typeof target == null){
return target
}
//拦截数组,给数组重写方法
if(Array.isArray(target)){
// Object.setPrototypeOf(target,proto)
target.__proto__ = proto
}
//循环重新定义data里面的属性和值
for (let key in target){
defineReactive(target,key,target[key])
}
}
//get和set方法
function defineReactive(target,key,value){
observer(value)//递归观察
Object.defineProperty(target,key,{
get(){
//需要进行依赖收集
return value
},
set(newValue){
if(value !== newValue){
observer(newValue)//更新后的数据也需要递归观察
updataView();
value = newValue
}
}
})
}
//模拟更新视图
function updataView(){
console.log("视图更新")
}
let data = {name:'fur',hobby:{play:"code"},age:[1,2,3]}
observer(data)
//三种写法,触发视图更新三次
data.hobby.play = {name:"js"}//视图更新
data.hobby.play.name = "ts"//视图更新
data.age = [1]//视图更新
vue2的缺陷很明显:
- 需要响应式的数据不能是新增属性
- 会多次嵌套递归,而且是一上来就递归,造成浪费,内存增大