网站首页 > java教程 正文
7个被重写的方法
在 Vue 的源代码中,数组类型重写了以下几个方法,以实现对数据变化的响应式处理:
- push:向数组末尾添加一个或多个元素,并返回新数组的长度。
- pop:删除数组的最后一个元素,并返回其值。
- shift:删除数组的第一个元素,并返回其值。
- unshift:向数组开头添加一个或多个元素,并返回新数组的长度。
- splice:从数组中添加或删除元素,并返回被删除的元素。
- sort:对数组元素进行排序并改变原数组。
- reverse:反转数组中的元素顺序。
这些方法被重写的目的是为了能够在对数组进行操作时,自动触发 Vue 的响应式系统,使得视图能够及时更新。这些重写的实现主要是在 Vue 的观察者(Observer)中进行处理。通过 Vue 的响应式系统,任何对数组的修改都会被捕获,从而更新相关的组件和视图。
后续源码分析都是依据 "version": "2.7.16" (vue2版本【最新版本】)和 "version": "3.5.12"【当前最新版本】 (vue3版本)分析的对比
重写的原因
- 数据驱动视图:Vue 的核心理念是数据驱动视图。当数据变化时,视图应当自动更新。重写数组的方法可以让 Vue 监控数组的变化,从而触发视图的更新。
- 响应式系统:对于数组的常用操作(如添加、删除元素),如果不重写这些方法,默认的 JavaScript 数组操作并不会通知 Vue 进行视图更新。重写这些方法可以捕获这些变更,确保 Vue 的响应式系统能够生效。
- 提高性能:Vue 通过使用虚拟 DOM 和差异算法来优化 DOM 更新。重写数组的方法也确保了只有当数据变化时,才会进行更新,从而提高了应用的性能。
- 一致性:通过重写数组的方法,Vue 确保了在处理数组时,所有操作都能保持一致,避免了不同类型数据处理机制的混乱。
源码体现
- github.com/vuejs/vue/b… (Vue2)
- github.com/vuejs/core/… (Vue3)
vue2中源码体现
const arrayProto = Array.prototype
// 创建一个新的对象 arrayMethods ,该对象继承自 Array.prototype,这样 arrayMethods 就可以使用数组原型上的所有方法
// 通过这种方式,可以在不影响原生数组的方法的情况下,给 arrayMethods 添加自定义的方法或进行其他扩展
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods, method, function mutator(...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
// notify change 通知变化
if (__DEV__) {
ob.dep.notify({
type: TriggerOpTypes.ARRAY_MUTATION,
target: this,
key: method
})
} else {
ob.dep.notify()
}
return result
})
})
vue3中源码体现
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse',
]
const patched = new WeakSet<object>()
/**
* 定义一个响应式属性,支持数组和对象
* @param obj 目标对象
* @param key 属性名
* @param val 属性值
*/
function defineReactive(obj: any, key: string, val: any) {
// it's possible for the original object to be mutated after being defined
// and expecting reactivity... we are covering it here because this seems to
// be a bit more common.
// 检查val是否为对象(排除原始数据类型),且val未被响应式处理过
// 如果val为对象,且未被响应式处理过,则将val转为响应式对象,并添加响应式处理标记
// 如果val为数组,则将数组方法转为响应式处理,并添加响应式处理标记
if (isObject(val) && !isReactive(val) && !patched.has(val)) {
const reactiveVal = reactive(val)
if (isArray(val)) {
methodsToPatch.forEach((m: any) => {
val[m] = (...args: any[]) => {
Array.prototype[m].apply(reactiveVal, args)
}
})
} else {
Object.keys(val).forEach(key => {
try {
defineReactiveSimple(val, key, val[key])
} catch (e: any) {}
})
}
}
const i = obj.$
if (i && obj === i.proxy) {
// target is a Vue instance - define on instance.ctx
defineReactiveSimple(i.ctx, key, val)
i.accessCache = Object.create(null)
} else if (isReactive(obj)) {
obj[key] = val
} else {
defineReactiveSimple(obj, key, val)
}
}
function defineReactiveSimple(obj: any, key: string, val: any) {
// 通过 isObject(val) 检查 val 是否为对象。如果是,则调用 reactive(val) 将其转换为响应式对象;如果不是,则保持原值
val = isObject(val) ? reactive(val) : val
Object.defineProperty(obj, key, {
enumerable: true, // 该属性可以被枚举
configurable: true, // 该属性可以被修改或删除
get() {
track(obj, TrackOpTypes.GET, key)
return val
},
set(newVal) {
// 判断新的值 newVal 是否为对象。如果是,调用 reactive(newVal) 进行转换;如果不是,直接赋值。
val = isObject(newVal) ? reactive(newVal) : newVal
trigger(obj, TriggerOpTypes.SET, key, newVal)
},
})
}
通过重写这些方法,Vue 能够提供一个高效、灵活的响应式系统,使得前端开发更加简单和直观。
- 上一篇: Excel中多行多列数据去重有高招
- 下一篇: PHP二维数组通过key去重
猜你喜欢
- 2024-11-22 Excel多列去重的两种方式
- 2024-11-22 js 数组去重复
- 2024-11-22 想要优雅的Excel数据去重,还得是unique函数
- 2024-11-22 自从学了深入解析java虚拟机:FullGC和字符串去重后,我无敌了
- 2024-11-22 携程 & 蘑菇街 & bilibili:手写数组去重、扁平化函数
- 2024-11-22 java数组的拷贝及Arrays类
- 2024-11-22 简单学Python——NumPy库7——排序和去重
- 2024-11-22 VBA数组与字典解决方案第44讲:利用字典排重,并提取不重复值
- 2024-11-22 php怎么用array_unique()函数去除数组中重复的值?
- 2024-11-22 List怎么去重?还只会用Set互换吗?一篇文章帮你打开“新世界”
你 发表评论:
欢迎- 最近发表
-
- 五,网络安全IDA Pro反汇编工具初识及逆向工程解密实战
- 「JAVA8」- Lambda 表达式(java lambda表达式原理)
- 深入探讨Java代码保护:虚拟机保护技术的新时代
- Nginx反向代理原理详解(图文全面总结)
- 逆向拆解日本IT,哪些Java技术栈薪资溢价高
- mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比
- Spring Boot集成ProGuard轻松实现Java 代码混淆, Java 应用固若金汤
- 从 Java 代码逆向工程生成 UML 类图和序列图
- 人与人相处:尊重是标配,靠谱是高配,厚道是顶配
- Windows系统安装日期如何修改(windows10怎么修改安装日期)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)