前端面试题:Vue2和Vue3的响应式原理实现

数据响应式:就是当数据发生变化时,vue会通知到使用该页面的代码。页面UI也发生相应的变化。

Vue2中的响应式原理:

通过object.defineProperty对对象的属性的读取、修改进行拦截(数据劫持),调用get和set对数据进行操作后返回。

数组类型:通过重写一系列数组的方法来实现拦截。

Object.defineProperty在获取对象属性和修改对象属性的时候会实现响应式,但是缺点是无法观察到新增数据和删除数据的变化。

Js 简易实现vue2响应式:

//源数据
let person = {
    name:'小明',
    age:58,
}
//模拟vue2中实现响应式
let p = {};
for (let key in person){
Object.defineProperty(p,key,{
    get(){
        console.log(`我读取了${key}属性`);
        return person.key;
    },
    set(value){
        console.log(`我修改了${key}属性,去更新界面`);
        person.key = value;
    }
})  
}

VUE3实现响应式:

通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。

通过Reflect(反射): 对源对象的属性进行操作。

Js 简易实现vue3响应式:

//源数据
let person = {
    name:'小明',
    age:58,
}
//vue3 proxy代理实现响应式原理
 const p = new Proxy(person,{
     //target:原对象  propName:参数名
    get(target,propName){
        console.log(`有人读取了p身上的${propName}属性${target}`);
        return target[propName];
    },
    set(target,propName,value){
        console.log(`有人修改了p身上的${propName}属性`);
        return target[propName] = value; 
    },
    deleteProperty(target,property){
        console.log(`有人删除了p身上的${propName}属性`);
        return delete target[property];
    }
 })

此时,响应式的实现大致完成,但还不是最完美的解决方案。例如:

const p1 = Object.defineProperty(person, "name", {
    get() {
        return "李四"
    }
})

// 此处出现异常
const p2 = Object.defineProperty(person, "name", {
    get() {
        return "王五"
    }
})
console.log(person)

上述代码,在重复对person 的 name 属性进行操作后,直接出现异常,导致单线程挂掉。如要解决以上问题,则需要用 try...catch 对异常进行捕获,非常的麻烦。

此时,我们可以使用Reflect 处理这种问题。

Reflect 是 window 上的内置构造函数,目前 ECMA 组织正尽力于把 Object 内置构造函数上的有用的 api 移植到 Reflect 之上,如:set()、get()、deleteProperty()…

与Object 不同的是,Reflect 会返回一个布尔值,可以更灵活地捕捉到异常,判断操作是否成功,从而进一步对错误进行抛出。

结合以上所述,实现响应式可优化为:

const p = new Proxy(person, {
    get(target, propName) {
        return Reflect.get(target, propName)
    },
    
    set(target, propName, value) {
        return Reflect.set(target, PropName, value)
    },
    
    deleteProperty(target, propName) {
        return Reflect.deleteProperty(target, PropName)
    }
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值