vue 读取txt_从Vue响应式原理到Proxy类

Vue作为一款现代前端三驾马车之一,快速高效深受大家的喜爱。我们在学习使用前端框架的同时,也多少需要掌握它的底层实现原理,不仅仅是因为它是面试常考题目,也对我们后续的开发之路提供了很好的引导和开阔视野的作用。今天这篇文章将从Vue2版本开始简单讲解Vue的响应式原理,和即将发布正式版的Vue3的实现差别。

56588f3df76234c7cef90de341b40a07.png

在Vue中,我们开发一个页面的时候,需要分别开发html模板js数据部分。而数据将直接渲染到模板中,而模板中的input输入值也可以直接反应到js数据中,这就是对响应式的简单解释。有了响应式,我们就只需要关心和处理数据,而无需关心如何去渲染他们。

Vue2的响应式原理

由于历史原因,Vue中使用的是ES5中对象方法 Object.defineProperty 来进行数据响应,他的作用可以为一个对象的某个字段添加拦截get/set方法,对该字段添加一个设置和读取的拦截操作:

let age = 18const obj = { age }Object.defineProperty(obj, 'age', {    get() {        return age + '岁'    },    set(value) {        age = value    }})console.log(obj.age) // "18岁"obj.age = 30console.log(obj.age) // "30岁"

使用Object.defineProperty方法监听obj中的age字段变化,当在外部读取obj.age时,将触发其中的get方法;当外部设置obj.age时,将触发set方法,并将设置的目标值传入。

注意:不能在Object.defineProperty中的get/set拦截方法中读取或设置当前监听的字段,这样会造成死循环。

到这里Vue2的响应式原理应该已经清晰了:将data对象中的每个字段都使用Object.defineProperty绑定监听事件,当监听到数据变化时,修改模板对应内容。

...html
// jslet text = ''const obj = { text }Object.defineProperty(obj, "text", {    get() {        return text;    },    set(value) {        text = value;        document.getElementById('txt').innerHTML = value;    }});document.getElementById('input').addEventListener('keyup', function (e) {    obj.text = e.target.value})

很容易就实现了简单的响应式渲染,利用这个方法,我们也能大概的想象出computed和watch的简单实现方式。但是这个方式有它的缺陷:

缺点1:不支持监听数组变化(元素、长度)

尤大重写了数组的几个函数,让每个原生函数都重新绑定响应事件,才让我们在Vue2中使用数组函数时,能够实现数组的响应式变化。

缺点2:不能监听字段的新增和删除

Object.defineProperty只能监听对象中已存在的字段,不能监听字段的新增和删除,所以在Vue中新增和删除都要使用$set方法重新绑定响应事。

缺点3:只能浅监听,无法监听更深层级的字段

只能监听最外层字段,如果想监听更深层,则需要递归绑定。

Vue3响应式原理

2020年5月,Vue3进入beta版本,意味着正式版距离我们越来越近,Vue3彻底重写,全面拥抱ES6,因为Object.defineProperty的种种缺陷,Vue3中使用ES6中新增的Proxy类进行数据响应式处理。

Object.defineProperty相同的是,Proxy 同样拥有get/set方法,可以监听获取和设置;但不同的是,Proxy不仅仅监听对象中的指定字段,而是监听某个对象的变化,这样就可以监听到字段的新增和删除了,可以说的质的变化;而且它还可以直接监听一个数组,数据拦截方式更加灵活多样。

还是上面第一段代码,我们使用Proxy重写:

const obj = { age: 18 }new Proxy(obj, {    get(target, key) {        return key in target ? target[key] + '岁' : `不存在${key}字段`    },    set(target, key, value) {        target[key] = value    }})console.log(obj.age) // "18岁"obj.age = 30console.log(obj.age) // "30岁"console.log(obj.name) // "不存在name字段"

还记得Object.defineProperty的死循环提示吗,在这样中就不需要关心这个问题,因为get/set方法中的target并不会循环触发监听对象的响应方法。

如果硬要为Proxy提一个缺点的话,那只能是ES6的兼容性比ES5差了(早已经不是问题了)。

更多

面试题 1:除了const,如何实现只读效果?

绑定响应拦截后不设置set方法

面试题 2:响应式原理有哪些应用?
  1. 数据拦截
  2. 计算属性
  3. 记录日志
  4. ...

如果你有更好的题目和思路,欢迎在评论区留言分享!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值