摘要:在读取访问器属性时,就会调用函数,该函数负责返回有效的值在写入访问器属性时,会调用函数并传入新值,该函数负责决定如何处理数据,但是这两个函数不一定非要同时存在。
前言
Vue最明显的特性之一便是它的响应式系统,其数据模型即是普通的 JavaScript 对象。而当你读取或写入它们时,视图便会进行响应操作。文章简要阐述下其实现原理,如有错误,还请不吝指正。个人博客链接:hiybm.cn
响应式data
{{ message }}const vm = new Vue({ el: "#exp", data: { message: "This is A" } }) vm.message = "This is B" // 响应式 vm._message = "This is C" // 非响应式
上述代码中,data是Vue实例的数据对象,当实例初始化时,Vue 会遍历 data 中的所有属性,并且使用 Object.definePropery 把这些属性全都转为 getter/setter ,从而让 data 的属性能够响应数据变化。另外,Object.defineProperty 是 ES5 中一个无法 shim(垫片) 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器的原因。对象必须是纯粹的对象 (含有零个或多个的 key/value 键值对):浏览器 API 创建的原生对象。所以,在data中声明过的message是响应式数据,而由于_message是在data外使用 Vue 实例增加的数据,所以亦不属于响应式。
关于Object.definePropery
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。这个API是实现响应式数据的关键所在。
Syntax: Object.defineProperty(obj, prop, descriptor)
obj: 要定义属性的对象
prop: 要定义或修改的属性的名称
descriptor: 将被定义或修改的属性描述符。
Tips: 要知道ECMAScript中有两种属性:数据属性和访问器属性。这里的descriptor可取值有数据属性和访问器属性。
数据属性: 包含一个数据值的位置,在此位置可以进行读写操作,有以下特性:
[[Configurable]]:对属性的操作可配置性开关,如删除,修改。默认值为true。
[[Enumberble]]:是否可枚举(通过for-in)。默认值为true。
[[Writable]]:能否修改属性的值。默认值为true。
[[value]]:包含这个属性的数据值,读取时从该位置读,写入时把新值存到该位置。默认值为undefined。
访问器属性: 不包含数据值,包含一个函数对(getter/setter)。特性如下:
[[Configurable]]:对属性的操作可配置性开关,如删除,修改。默认值为true。
[[Enumberble]]:是否可枚举(通过for-in)。默认值为true。
[[Get]]:读取属性时调用的函数。默认值为undefined。
[[Set]]:写入属性时调用的函数。默认值为undefined。
Tips: 在读取访问器属性时,就会调用getter函数,该函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,该函数负责决定如何处理数据,但是这两个函数不一定非要同时存在。Vue便是利用getter/setter这一特性来实现的响应系统。
示例代码:
// 定义一个book对象,_year和edition都属于数据属性。 var book = { _year : 2004, edition : 1 }; // 对book对象创建 year 访问器属性。 Object.defineProperty(book, "year",{ // 读取 year 访问器属性时,get() 方法返回 _year 的值。 get : function () { console.info(this._year, "get"); // 2004 return this._year; }, // 写入 year 访问器属性时,set() 方法对新值进行操作。 set : function (newValue) { if (newValue > 2004) { this._year = newValue; console.info(this._year, "set") // 2005 this.edition += newValue - 2004; } } }); // 读取 year 访问器属性时会返回_year的值。 book.year; // 写入 year 访问器属性时会调用set() 函数,进行操作。 book.year = 2005; console.info(book.edition) // 2 console.info(book) // 此处藏有彩蛋。
watcher
官方表述:每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
如下图所示:
Tips:模板中每个指令/数据绑定都有一个对应的 watcher 对象。其中 watcher扮演的角色相当于是一个纽带,这个纽带的作用就是依赖收集。
END
文中还有部分深层细节没有讲述到,后续我也会接着更新系列文章来进一步深深深究vue底层的响应式原理,SYNT。BTW,如果有同学发现彩蛋了,欢迎在评论区交流。?
参考链接
Object.defineproperty
深入响应式原理
深入浅出之vue响应式原理
Javascript高级程序设计(第3版)6.1章节
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/90258.html
摘要:问题为什么修改即可触发更新和的关联关系官方介绍的官网文档,对响应式属性的原理有一个介绍。因此本文在源码层面,对响应式原理进行梳理,对关键步骤进行解析。 描述 我们通过一个简单的 Vue应用 来演示 Vue的响应式属性: html: {{message}} js: let vm = new Vue({ el: #ap...
摘要:所以我今后打算把每一个内容分成白话版和源码版。有什么错误的地方,感谢大家能够指出响应式系统我们都知道,只要在实例中声明过的数据,那么这个数据就是响应式的。什么是响应式,也即是说,数据发生改变的时候,视图会重新渲染,匹配更新为最新的值。 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 V...
写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】Props - 源码版 今天记录 Props 源码流程,哎,这东西,就算是研究过了,也真是会随着时间慢慢忘记的。 幸好我做...
摘要:原型方法通过原型方法方法来挂载实例。当响应式属性发生变化时,会通知依赖列表中的对象进行更新。此时,对象执行方法,重新渲染节点。在执行过程中,如果需要读取响应式属性,则会触发响应式属性的。总结响应式属性的原理 vue实例 初始化 完成以后,接下来就要进行 挂载。 vue实例挂载,即为将vue实例对应的 template模板,渲染成 Dom节点。 原型方法 - $mount 通过原...
摘要:对象用户看到的对象用户看到的是这个对象即是实际使用的对象实际使用的对象复制更新相应的代码实现对象代理响应式原理前提官网说过,限于现代浏览器限制,无法监测通过这种方式添加的属性,所以,他的响应式是建立在实例化对象的时候,预定义属性的基础上的。 1. Vue 对象 1.1 用户看到的对象 var app = new Vue({ el: #app , /* * 用...
阅读 2992·2023-04-25 20:09
阅读 3296·2021-11-23 09:51
阅读 1953·2021-11-22 15:25
阅读 3327·2021-11-18 10:02
阅读 2731·2021-09-27 13:56
阅读 1287·2019-08-30 15:44
阅读 1134·2019-08-30 13:21
阅读 3291·2019-08-30 11:05