DDR爱好者之家 Design By 杰米
这篇文章主要是给不了解或者没接触过 vue 响应式源码的小伙伴们看的,其主要目的在于能对 vue 的响应式原理有个基本的认识和了解,如果在面试中被问到此类问题,能够知道面试官想让你回答的是什么?「PS:文中如有不对的地方,欢迎小伙伴们指正」
响应式的理解
响应式顾名思义就是数据变化,会引起视图的更新。这篇文章主要分析 vue2.0 中对象和数组响应式原理的实现,依赖收集和视图更新我们留在下一篇文章分析。
在 vue 中,我们所说的响应式数据,一般指的是数组类型和对象类型的数据。vue 内部通过 Object.defineProperty 方法对对象的属性进行劫持,数组则是通过重写数组的方法实现的。下面我们就简单实现一下。
首先我们定义一个需要被拦截的数据
const vm = new Vue({ data () { return { count: 0, person: { name: 'xxx' }, arr: [1, 2, 3] } } }) let arrayMethods function Vue (options) { // 这里只考虑对 data 数据的操作 let data = options.data if (data) { data = this._data = typeof data === 'function' "htmlcode">class Observer { constructor (data) { Object.defineProperty(data, '__ob__', { // 在 data 上定义 __ob__ 属性,在数组劫持里需要用到 enumerable: false, // 不可枚举 configurable: false, // 不可配置 value: this // 值是 Observer 实例 }) if (Array.isArray(data)) { // 对数组进行拦截 data.__proto__ = arrayMethods // 原型继承 this.observerArray(data) } else { // 对象进行拦截 this.walk(data) } } walk (data) { const keys = Object.keys(data) for(let i = 0; i < keys.length; i++) { const key = keys[i] defineReactive(data, key, data[key]) } } observerArray (data) { // 拦截数组中的每一项 data.forEach(value => observer(value)) } }对象的拦截
对象的劫持需要注意的几点:
- 遍历对象,如果值还是对象类型,需要重新调用 observer 观测方法
- 如果设置的新值是对象类型,也需要被拦截
// 处理对象的拦截 function defineReactive(data, key, value) { observer(value) // 如果 value 值仍是对象类型,需要递归劫持 Object.defineProperty(data, key, { get() { return value }, set(newValue){ if (newValue === value) return value = newValue observer(newValue) // 如果设置 newValue 值也是对象类型,需要被劫持 } }) }
数组的劫持
数组的劫持需要注意的几点:
- 数组是使用函数劫持(切片编程)的思想,对数据进行拦截的
- 数组里新增加的值,如果是对象类型,也需要被重新拦截
const oldArrayPrototype = Array.prototype arrayMethods = Object.create(oldArrayPrototype) const methods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'] // 能够改变原数组的方法 methods.forEach(method => { arrayMethods[methods] = function (...args) { const result = oldArrayPrototype[methods].call(this, ...args) const ob = this.__ob__ // this 就是调用改方法的数组 let inserted; // 数组新增的项的集合,需要再对其进行拦截 switch(methods) { case 'push': case 'unshift': inserted = args case 'splice': inserted = args.slice(2) // 因为 splice 第二个参数后面的才是新增的 } if (inserted) { ob.observerArray(inserted) } return result } })
原理总结
在面试中,如果我们需要手写 vue 的响应式原理,上面的代码足矣。但是我们通过学习 vue 的源码,如果在面试中能够给出以下加以总结性的回答更能得到面试官的青睐。
vue 2.0 源码的响应式原理:
- 因为使用了递归的方式对对象进行拦截,所以数据层级越深,性能越差
- 数组不使用 Object.defineProperty 的方式进行拦截,是因为如果数组项太多,性能会很差
- 只有定义在 data 里的数据才会被拦截,后期我们通过 vm.newObj = 'xxx' 这种在实例上新增的方式新增的属性是不会被拦截的
- 改变数组的索引和长度,不会被拦截,因此不会引起视图的更新
- 如果在 data 上新增的属性和更改数组的索引、长度,需要被拦截到,可以使用 $set 方法
- 可以使用 Object.freeze 方法来优化数据,提高性能,使用了此方法的数据不会被重写 set 和 get 方法
vue 3.0 源码响应式原理:
- 3.0 版本中使用了 proxy 代替了 Object.defineProperty ,其有13中拦截方式,不需要对对象和数组分别进行处理,也无需递归进行拦截,这也是其提升性能最大的地方
- vue 3.0 版本响应式原理的简单实现
const handler = { get (target, key) { if (typeof target[key] === 'object' && target[key] !== null) { return new Proxy(target[key], handler) } return Reflect.get(target, key) }, set (target, key, value) { if(key === 'length') return true console.log('update') return Reflect.set(target, key, value) } } const obj = { arr: [1, 2, 3], count: { num: 1 } } // obj 是代理的目标对象, handler 是配置对象 const proxy = new Proxy(obj, handler)
DDR爱好者之家 Design By 杰米
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
DDR爱好者之家 Design By 杰米
暂无评论...
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
2024年11月23日
2024年11月23日
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]