Vue 数据响应 Object.defineProperty
Vue 数据响应
在网页开发中,一般数据想要渲染到页面中,需要依赖于操作 DOM 更新。 Vue
和React
则是使用数据驱动视图,也就是数据改变,DOM 也相应完成变化。
而数据变化更新 DOM 也分为侵入式和非侵入式
侵入式和非侵入式
Vue
属于非侵入式,React
和小程序
数据变化输入侵入式。
侵入式设计,就是设计者将框架功能“推”给客户端;
而非侵入式设计,则是设计者将客户端的功能“拿”到框架中用
侵入式设计带来的最大缺陷是,代码需要依赖框架的代码,如果把框架拿掉或者换一个框架,就需要重新修改代码
下面的例子中,vue
改变 a 的值没有调用其他的 API,而react
和小程序
则调用了setState
和setData
的 API
Vue:
React:
小程序:
Object.defineProperty() 数据代理
当然,本文的重点在于 Object.defineProperty。
在上面说到,在React
和小程序当中,因为调用 API 方法改变数值,所以界面改变也很好理解,API 方法对应会改变 DOM。
那么Vue
改变数值时是非侵入式,那么界面应该响应数值改变而改变?
在这里就需要提到Object.defineProperty
数据代理了,MDN 地址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
这是一个 JavaScript 引擎的 API,可以来检测对象属性的变化
在 vue3 中使用 proxy 代替
defineProperty
,但是 proxy 具有兼容性问题,且无法 polyfill (基本上 IE 浏览器可以放弃)参考: https://caniuse.com/?search=proxy
之前在《前端面试中有趣的题目》 中也有用到过该方法去定义一个 const
Object.defineProperty
中具有 get 和 set 方法,当 Vue 去改变 a 值时,a 属性已经被 set 给劫持了。(get 和 set 都需要变量进行周转)
例子: 在下面会看到例子当中 obj 对象存在一个_a
属性,这是为了对应之后设置a
的get
和set
,现在修改obj.a
的数值,也能够打印console
中的语句。如果在set
方法中添加updateView
更新视图方法,那么就能够简单的达到了数据同步的效果
封装一个 defineProperty 方法
先定义一个等一下要测试的数据
在上面的基础上,可以对其进行封装
对其中的name
属性调用方法进行代理,能够在控制台看到name的原值zhangsan被更新为:lisi
被打印
并且在此封装好的基础上,可以再写一个方法,对对象进行分析,遍历对象各个属性放入方法代理
这样一来层次不深的属性
基本已经被 defineProperty 代理了
不过如果是内部还有层次的就不行了,比如下面的例子,就没有打印出来
那么就对属性再做一次判断,如果还是对象,继续遍历
这样一来address的原值江苏被更新为:浙江
就能够被打印出来了
Object.defineProperty 缺点
Object.defineProperty
还是有挺多不足的
比如上面说到的深度监听,需要递归到底,一次性的计算量很大。
无法监听新增属性/删除属性 (所以在 vue 中会有
Vue.set
和Vue.delete
)数据劫持并不能对数组的
push
、shift
等方法生效生效,无法原生监听数组,需要特殊处理
版权声明: 本文为 InfoQ 作者【空城机】的原创文章。
原文链接:【http://xie.infoq.cn/article/8f008f59b172f71d6903a467c】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论