vue2.x版本中Object.defineProperty对象属性监听和关联
前言
在vue2.x版本官方文档中
深入响应式原理 https://cn.vuejs.org/v2/guide/reactivity.html一文的解释当中,Object.defineProperty将声明响应式 property数据的状态转换为getter和setter。
Object.defineProperty基本使用和概念
官方解释的概念是
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
Object.defineProperty(obj, prop, descriptor)
obj: 要在其上定义属性的对象
prop: 要定义或修改的属性的名称或Symbol
descriptor: 定义或修改的属性的描述符
* @descriptor
*
* configurable 为 true 时,属性才能重新被定义,默认为 false。
* enumerable 为 true 时,该属性才能够出现在对象的枚举属性中,此时才能通过for in遍历属性。默认为 false。
* writable 为 true 时,value属性值才能被修改。默认为 false,此时value属性值为只读状态。
* value 该属性对应的初始值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
* get 一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行。默认为 undefined。
* set 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。默认为 undefined。
* 注意事项:get 和 set 它们与value和writable是互斥的。一旦使用它们,则这个属性就没有保存属性值的能力
Object.defineProperty新增对象属性
let userInfo = {
age: "11",
};
console.log("初始userInfo:", userInfo);
// Object.defineProperty新增对象属性
Object.defineProperty(userInfo, "name", {
value: "zhangsan",
enumerable: true, //将enumerable设为true 才能够出现在对象的枚举属性
});
console.log("设置name后的userInfo:", userInfo);
console.log("设置name后的userInfo属性:", Object.keys(userInfo));
当enumerable设置为false的时候,我们通过Object.keys枚举属性,并不能获取到name属性
使用Object.defineProperty修改和监听属性值的变化
let userInfo = {
age: "11",
};
let initAge = null;
Object.defineProperty(userInfo, "age", {
enumerable: true,
configurable: true,
get: function () {
console.log("get属性方法,当前对象:", this);
return initAge;
},
set: function (newValue) {
console.log("set属性方法", newValue);
initAge = newValue;
},
});
userInfo.age = "30";
console.log("最后userInfo", userInfo);
通过get和set操作对象属性类似于我们在vue开发过程中的计算属性computed详解,通过get和set对当前对象进行设置属性值
Object.defineProperty小结
- 由上面的的例子我们可以知道,当我们使用Object.defineProperty操作对象的时候,都是直接通过对象属性进行操作,而不是对整个对象进行修改,删除和新增,查询属性
- 在使用Object.defineProperty方法操作的时候,一些默认的属性选项,需要我们注意
Object.defineProperty和vue2.x的联系
回到开头提到的官方文档中描述的,响应式原理中,如下图
图片源自vue官方文档深入响应式原理: https://cn.vuejs.org/v2/guide/reactivity.html
当组件渲染时,通过对象劫持,遍历data状态,那么需要考虑的点是:
假如在组件运行时,我们需要额外添加状态的时候,添加一个新的状态,或者在原有的状态下,添加一个新的属性会发生什么,这个新的状态并不在组件劫持的状态之内:
<p>
<span style="cursor: pointer; color: red" @click="handleUser"
>点击修改不在data状态下的值</span
>
</p>
<p>用户信息: name {{ defaultUser.name }}, age: {{ defaultUser.age }}</p>
data() {
return {
defaultUser: {
name: "张三",
},
};
},
methods: {
handleUser() {
this.defaultUser.age = "23";
console.log("数据已经发生更改,但是视图没有发生更新", this.defaultUser);
},
},
当我们点击按钮的时候,视图中的ui并没有发生更改,根据官方的文档,我们可以使用 $set 针对新增的状态进行修改
<p>
<span style="cursor: pointer; color: red" @click="handleSet"
>点击$set修改属性值</span
>
</p>
<p>通过$set修改的值:{{ setData.name }}</p>
data() {
return {
setData: {},
};
},
methods: {
handleSet() {
this.$set(this.setData, "name", "张三");
},
},
除了后续新增的状态无法进行修改之外,使用Object.defineProperty劫持的数据,对数组本身可以操作的到,但是会存在一定的性能问题,具体不做详细解释,可以参考以下博文,感谢该博主的博文,vue的框架的作者尤大也做了解释:
记一次思否问答的问题思考:Vue为什么不能检测数组变动 https://segmentfault.com/a/1190000015783546
结语
根据以上例子结合vue响应式原理,我们可以知道在vue2.x版本中Object.defineProperty存在以下问题:
1.监听数组变化下存在性能问题
2.Object.defineProperty只能劫持对象的属性,并且针对新增的data状态,无法劫持到,只能通过vue的扩展方法$set进行处理
扩展vue3使用的proxy
阮一峰-ECMAScript 6 入门
查看最简单的例子和使用方法
下文截取自:阮一峰-ECMAScript 6 入门----> Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”
var obj = new Proxy({}, {
get: function (target, propKey, receiver) {
console.log(`getting ${propKey}!`);
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log(`setting ${propKey}!`);
return Reflect.set(target, propKey, value, receiver);
}
});
Object.defineProperty对比Proxy个人理解
- Proxy是针对整个对象的变化进行检测和拦截,可以知道对象的属性是新增,删除,还是修改等,都可以通过通过get和set进行监听得到
- Object.defineProperty只针对对象得属性进行操作,结合vue2.x,组件渲染完成,后续新增得属性,没办法劫持到
- Object.defineProperty针对属性,Proxy针对整个对象得操作
更多Object.defineProperty和Proxy的对比,以及vue3如果使用proxy实现对象的监听,感兴趣的同学可以去搜索相关博文,后续有时间再整理。
源码地址
文章个人博客地址:vue2.x版本中Object.defineProperty对象属性监听和关联
欢迎关注公众号:程序猿布欧,不定期更新一些前端入门文章
创作不易,转载请注明出处和作者。
vue2.x版本中Object.defineProperty对象属性监听和关联的更多相关文章
- vue对象属性监听
对象属性监听的两种方法: 1.普通的watch data() { return { frontPoints: 0 } }, watch: { frontPoints(newValue, oldValu ...
- js中Object.defineProperty()和defineProperties()
在介绍js中Object.defineProperty()和defineProperties()之前,我们了解下js中对象两种属性的类型:数据属性和访问器属性. 数据属性 数据属性包含一个数据的位置, ...
- vue2.x版本中computed和watch的使用入门详解-watch篇
前言 watch顾名思义,属于vue2.x版本中,监听和观察组件状态变化的钩子函数,常见的应用场景有监听路由变化,以及父组件传递给子组件的props数据的变化等 基本使用 在使用watch的时候,需要 ...
- vue2.x版本中computed和watch的使用入门详解-关联和区别
前面两篇介绍了computed和watch的基本使用 watch篇 computed篇 两者的区别,继续通过代码实现的方式具体去了解 html <li>最开始的value值:{{ name ...
- vue2.x版本中computed和watch的使用入门详解-computed篇
前言 在基于vue框架的前端项目开发过程中,只要涉及到稍微复杂一点的业务,我们都会用到computed计算属性这个钩子函数,可以用于一些状态的结合处理和缓存的操作. 基础使用 在computed中,声 ...
- CorelDRAW中如何复制对象属性详解
复制对象属性是一种比较特殊.重要的复制方法,它可以方便而快捷地将指定对象中的轮廓笔.轮廓色.填充和文本属性通过复制的方法应用到所选对象中.本教程将详解CorelDRAW中如何复制对象属性. Corel ...
- 微信小程序实现watch属性监听数据变化
Vue 提供了一种通用的方式来观察和响应 Vue 实例上的数据变动:监听属性 watch. 虽然watch的滥用会导致性能不佳,但在一些情况下我们还是需要watch,使得代码更加简洁.逻辑更加清晰(其 ...
- 迷你MVVM框架 avalonjs 学习教程15、属性监听与模块通信
avalon的ViewModel对象从其内部EventManager里继承了三个方法,$watch.$unwatch.$fire三个方法,它们就是我们本节的主题. 词如其名,非常直白,一看就知道做什么 ...
- JavaEE开发之Spring中的事件发送与监听以及使用@Profile进行环境切换
本篇博客我们就来聊一下Spring框架中的观察者模式的应用,即事件的发送与监听机制.之前我们已经剖析过观察者模式的具体实现,以及使用Swift3.0自定义过通知机制.所以本篇博客对于事件发送与监听的底 ...
随机推荐
- 简述synchronized和java.util.concurrent.locks.Lock的异同 ?
主要相同点:Lock能完成synchronized所实现的所有功能 主要不同点:Lock有比synchronized更精确的线程语义和更好的性能.synchronized会自动释放锁,而Lock一定要 ...
- SpringCloud和Dubbo?
SpringCloud和Dubbo都是现在主流的微服务架构SpringCloud是Apache旗下的Spring体系下的微服务解决方案Dubbo是阿里系的分布式服务治理框架从技术维度上,其实Sprin ...
- IDEA 错误:程序包XXX不存在
第一种情况是:JDK版本不对,需要确认是否一致 第二种情况是:确认一下此菜单项是否启用Enabled 第三种情况:确认包目录是否标识为Java源目录 第四种情况:如果使用的是Gradle,确认以下配置 ...
- 什么是可重入锁ReentrantLock?
举例来说明锁的可重入性 public class UnReentrant{ Lock lock = new Lock(); public void outer(){ lock.lock(); inne ...
- LIKE 声明中的%和_是什么意思?
%对应于 0 个或更多字符,_只是 LIKE 语句中的一个字符. 如何在 Unix 和 MySQL 时间戳之间进行转换? UNIX_TIMESTAMP 是从 MySQL 时间戳转换为 Unix 时间戳 ...
- 文件缓存tmpfs + 数据缓存SSDB(一)
一.文件缓存tmpfs 1.特性 1) 基于内存的文件系统,RAW+SWAP,虚拟内存 2) tmpfs使用虚拟内存,/dev/shm/使用共享内存 3) 访问速度快,可以动态调整大小 4) 没有持久 ...
- Visual Studio App Center 中的 Bug 跟踪服务
我在之前的一篇文章 <使用 Visual Studio App Center 持续监视应用使用情况和问题> 中介绍了 App Center 的基本功能及使用入门,其中 诊断 可以自动手机用 ...
- 玩转 React(四)- 创造一个新的 HTML 标签
在第二篇文章 <新型前端开发方式> 中有说到 React 有很爽的一点就是给我们一种创造 HTML 标签的能力,那么今天这篇文章就详细讲解下 React 是如何提供这种能力的,作为前端开发 ...
- html5 canvas基础10点
本文主要讲解下一些canvas的基础 1.<canvas id="canvas">若此浏览器不支持canvas会显示该文字</canvas> //创建个ht ...
- 微信小程序上拉加载:onReachBottom详解+设置触发距离
前端经常遇到上拉加载更多的需求,一般还涉及到翻页.小程序里已经给了下拉到底的触发方法onReachBottom(),这里记录下怎样使用这个方法实现下拉加载更多,有需要的直接看代码,有详细注释: 1.首 ...