Vue2响应式原理|环球视点
响应式基本原理就是,在初始化vue实例的时候,对data的每一个属性都通过Object defineProperty定义一次,在数据被set的时候,做一些操作,改变相应的视图
Vue.js 基本上遵循 MVVM(Model–View–ViewModel)架构模式,数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。 本文讲解一下 Vue 响应式系统的底层细节。
检测变化注意事项由于 JavaScript 的限制,这个 Object.defineProperty() api 没办法监听数组长度的变化,也不能检测数组和对象的新增变化。Vue 无法检测通过数组索引直接改变数组项的操作,这不是 Object.defineProperty() api 的原因,而是尤大认为性能消耗与带来的用户体验不成正比。对数组进行响应式检测会带来很大的性能消耗,因为数组项可能会大,比如1000条、10000条。响应式原理Vue 2.0中,是基于 Object.defineProperty 实现的响应式系统 (这个方法是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因)vue3 中,是基于 Proxy/Reflect 来实现的
响应式基本原理就是,在 Vue 的构造函数中,对 options 的 data 进行处理。即在初始化vue实例的时候,对data、props等对象的每一个属性都通过 Object.defineProperty 定义一次,在数据被set的时候,做一些操作,改变相应的视图。
(相关资料图)
让我们基于 Object.defineProperty 来实现一下对数组和对象的劫持。
import { newArrayProto } from "./array"class Observer { constructor(data){ if (Array.isArray(data)) { // 这里我们可以重写可以修改数组本身的方法 7个方法,切片编程:需要保留数组原有的特性,并且可以重写部分方法 data.__proto__ = newArrayProto this.observeArray(data) // 如果数组中放的是对象 可以监控到对象的变化 } else { this.walk(data) } } // 循环对象"重新定义属性",对属性依次劫持,性能差 walk(data) { Object.keys(data).forEach(key => defineReactive(data, key, data[key])) } // 观测数组 observeArray(data) { data.forEach(item => observe(item)) }}function defineReactive(data,key,value){ observe(value) // 深度属性劫持,对所有的对象都进行属性劫持 Object.defineProperty(data,key,{ get(){ return value }, set(newValue){ if(newValue == value) return observe(newValue) // 修改属性之后重新观测,目的:新值为对象或数组的话,可以劫持其数据 value = newValue } })}export function observe(data) { // 只对对象进行劫持 if(typeof data !== "object" || data == null){ return } return new Observer(data)}
重写数组7个变异方法7个方法是指:push、pop、shift、unshift、sort、reverse、splice。(这七个都是会改变原数组的)
实现思路:面向切片编程!!!
不是直接粗暴重写 Array.prototype 上的方法,而是通过原型链继承与函数劫持进行的移花接木。
利用 Object.create(Array.prototype) 生成一个新的对象 newArrayProto,该对象的 __proto__指向 Array.prototype,然后将我们数组的 __proto__指向拥有重写方法的新对象 newArrayProto,这样就保证了 newArrayProto 和 Array.prototype 都在数组的原型链上。
arr.__proto__ === newArrayProto;newArrayProto.__proto__ === Array.prototype
然后在重写方法的内部使用 Array.prototype.push.call 调用原来的方法,并对新增数据进行劫持观测。
let oldArrayProto = Array.prototype // 获取数组的原型export let newArrayProto = Object.create(oldArrayProto)// 找到所有的变异方法let methods = ["push", "pop", "shift", "unshift", "reverse", "sort", "splice"]methods.forEach(method => { // 这里重写了数组的方法 newArrayProto[method] = function (...args) { // args reset参数收集,args为真正数组,arguments为伪数组 const result = oldArrayProto[method].call(this, ...args) // 内部调用原来的方法,函数的劫持,切片编程 // 我们需要对新增的数据再次进行劫持 let inserted let ob = this.__ob__ switch (method) { case "push": case "unshift": // arr.unshift(1,2,3) inserted = args break case "splice": // arr.splice(0,1,{a:1},{a:1}) inserted = args.slice(2) default: break } if (inserted) { // 对新增的内容再次进行观测 ob.observeArray(inserted) } return result }})
增加__ob__属性这是一个恶心又巧妙的属性,我们在 Observer 类内部,把 this 实例添加到了响应式数据上。相当于给所有响应式数据增加了一个标识,并且可以在响应式数据上获取 Observer 实例上的方法
class Observer { constructor(data) { // data.__ob__ = this // 给数据加了一个标识 如果数据上有__ob__ 则说明这个属性被观测过了 Object.defineProperty(data, "__ob__", { value: this, enumerable: false, // 将__ob__ 变成不可枚举 (循环的时候无法获取到,防止栈溢出) }) if (Array.isArray(data)) { // 这里我们可以重写可以修改数组本身的方法 7个方法,切片编程:需要保留数组原有的特性,并且可以重写部分方法 data.__proto__ = newArrayProto this.observeArray(data) // 如果数组中放的是对象 可以监控到对象的变化 } else { this.walk(data) } }}
__ob__有两大用处:
如果一个对象被劫持过了,那就不需要再被劫持了,要判断一个对象是否被劫持过,可以通过__ob__来判断// 数据观测export function observe(data) { // 只对对象进行劫持 if (typeof data !== "object" || data == null) { return } // 如果一个对象被劫持过了,那就不需要再被劫持了 (要判断一个对象是否被劫持过,可以在对象上增添一个实例,用实例的原型链来判断是否被劫持过) if (data.__ob__ instanceof Observer) { return data.__ob__ } return new Observer(data)}
我们重写了数组的7个变异方法,其中 push、unshift、splice 这三个方法会给数组新增成员。此时需要对新增的成员再次进行观测,可以通过__ob__调用 Observer 实例上的 observeArray 方法 标签:
响应式基本原理就是,在初始化vue实例的时候,对data的每一个属性都通过Object defineProperty定义一次,在数据被set的时候,做一些操作,改变相应的视图
浏阳日报讯(记者徐旻通讯员钟娟)3月20日,浏阳市2023年首期创业培
1、大明湖,山东省济南市区湖泊、济南三大历史名胜之一。位于济南市历下区旧城区北部,是由济南众多泉水汇流而成,湖水经泺水河注入小清河。湖
3月23日,上海证券交易所披露关于保利发展控股集团股份有限公司(600048 SH)向特定对象发行股票申请文件的审核问询函。根据问询函内容,申报材
陈恢清在海绵城市建设暨雨污分流工作调度会上强调创造性抓落实高水平建设海绵城市3月23日,我市召开海绵城市建设暨雨污分流工作调度会。市委副
品玩3月24日讯,据theVerge报道,Snap公司成立了一个新部门,主要负责为其它公司的网站或APP构建AR功能。该部门名为AR企业服务(ARES),负责
学校不得安排未成年人参加商业活动---昨日(3月23日),市十六届人大常委会第二次会议召开,会议听取审议了《北京市未成年人保护条例(修订草
1、16:线程的定义真的很多,每个学科的定义都不一样。这里有一个定义:它是一个程序内的顺序控制流,当涉及到线程时,它会谈
摘要:基于深度学习的瓶盖检测系统用于传送带或日常场景中瓶盖检测识别,提供实时瓶盖检测定位和计数,辅助瓶盖生产加工过程的自动化识别。本
1、“壮族三月三”不仅是广西壮族重要的传统习惯节日,也是汉、瑶、苗、侗、仫佬、毛南等世居民族重要的传统习惯节日。主要集中在南宁、柳...
2023年灵活就业缴费档次注意到有灵活就业人员存在这样的误区,那就是趁着当地还没有公布2023年缴费标准钱,赶紧将一年的费用交了,以后涨钱了
今年以来,各地掀起“博物馆热”,处处可见排队观展的火热场面。各大博物馆也纷纷拿出镇馆之宝,并创新观展方式,让观众看得过瘾,玩得高兴...
在进行PHP开发前,需要搭建PHP环境。对于Mac用户来说,这个过程相对简单,以下是如何在Mac上安装PHP环境的详细步骤。
“你爱我吗?”陈晖洁问。她和布莱克躺在床上。“为什么问这个呢?”布莱克翻过身撑起来,湖蓝色的眼睛温柔地看着她。换做以前,陈晖洁很喜...
“小红书,到底是在哪里看直播带货?”张然是小红书三年用户,平时把小红书当成“种草”的搜索引擎,每次想买护肤品、买衣服、找餐馆,都先...
皮肤肤色较暗的人适合一些茶褐色系、浅色调、明亮的衣服,如浅黄、浅粉、米白等色彩的衣服,看起来更有个性,墨绿、枣红、啡色、金黄色将看起
1、长期以来,人们一直认为,金字塔就是法老胡夫的陵墓,其证据是大金字塔的碑文和铭文上刻有胡夫的名字。2、可是据文献记载,公元810年,阿拉
1、《晚明心学思潮与士风变异研究》是花木蘭文化出版的图书。2、作者是李興源。文章到此就分享结束,希望对大家有所帮助。
1、榄香脂是一种得于热带橄榄科(Burseraceae)树种的软树脂(RESIN)。2、由于榄香脂可增强以坚硬而易碎树脂所制成的上光油的弹性和坚硬度,因
一个月前,吉利汽车宣布最新的混动专用1 5T四缸机正式下线,预示着现役以三缸机为基础的雷神Hi·X(参数|询价)混动(吉利品牌)、LynkE-Motive混动(
重大项目是扩大有效投资的有力抓手。新疆着眼于构建支撑高质量发展的现代化基础设施体系,一批投资体量大、产业链条长、辐射带动强的重大项目
1、《仙剑奇侠传2》剧情介绍:二代故事是于一代的八年后,当初与李逍遥住在同一个村子的邻居,王小虎,已经是一位十八岁的成熟青年。2、想当年
1、(二)需要开通网上认证业务的,还需持U盘到主管国税机关办税服务厅领取密钥。2、(三)需要开通网上缴税业务的,还需到主
1、萨尔运动(Saalicorogeny)曾译萨阿尔运动,由史蒂勒(H·Stille)于1924年创名。是海西构造
现款高尔夫2011款1 4TSI自动豪华型2012年高尔夫6的变化高尔夫6的所有车型都将以全向驻车雷达取代驻车雷达高尔夫
外国人追星其实也很疯狂,一点不比中国的粉丝弱,李子柒现如今在国际上的名声越来越大,在国外也吸引了一大波的粉丝。在李子柒的最新视频,成
每个省份的分数线都不一样,那么高考考上本科大概需要多少分?高考下面是由本站编辑为大家整理的“高考多少分能上本科本科分数线是多少”。...
观点网讯:3月22日,中铁建资产管理有限公司发行的“中铁建资产管理有限公司2023年面向专业投资者公开发行可续期公司债券
内蒙古沙尘暴高速还能上高速吗?由于受大风扬沙、部分路段降雪天气影响,内蒙古境内部分高速路段实时交通管制。发布时间:2023-03-2210:30:002023
3月22日,2023全球6G技术大会开幕。本次大会以“6G融通世界,携手共创未来”为主题,由国家6G技术研发推进工作组和总体专家组指导,由未来...