您现在的位置是:亿华云 > 系统运维
Vue3源码解析计划之计算属性为什么比普通函数妙?
亿华云2025-10-09 01:17:17【系统运维】7人已围观
简介本文转载自微信公众号「前端万有引力」,作者 一川 。转载本文请联系前端万有引力公众号。写在前面计算属性是Vue开发中一个非常实用的API,它允许用户自定义一个计算方法,然后根据一些依赖的响应式数据计算
本文转载自微信公众号「前端万有引力」,码解作者 一川 。析计转载本文请联系前端万有引力公众号。计算
写在前面
计算属性是属性数妙Vue开发中一个非常实用的API,它允许用户自定义一个计算方法,比普然后根据一些依赖的通函响应式数据计算出新值并返回。当依赖发生变化时,码解计算属性会自动重新计算获取新值,析计使用方便。计算我们看出计算属性本质上是属性数妙对依赖的计算,为什么不直接使用函数呢?比普在Vue3中的计算属性又是如何实现的呢?
计算属性 computed
我们先简单看个例子,我们看到再设置了计算属性addOne后,通函直接改变addOne.value的码解值会报错,只能通过改变原始值count.value才不会报错。析计这是计算因为:
如果传递给computed的是一个函数,那就是一个getter函数,只能获取它的值,而不能直接修改它 在getter函数中,根据响应式对象重新计算出新值,叫做计算属性,网站模板这个响应式对象叫做计算属性的依赖 const count = ref(1); const addOne = computed(()=>count.value+1); console.log(addOne.value);//2 addOne.value++;//error count.value++; console.log(count.value);//3那么,我们应该如何修改addOne.value值呢?那就是在computed中设置set函数,进行自定义修改值。
const count = ref(1); const addOne = computed({ get:()=>count.value+1, set:val=>count.value=val-1 }); addOne.value = 1; console.log(count.value);//0我们研究源码:
export function computed<T>( getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T> ) { let getter: ComputedGetter<T> let setter: ComputedSetter<T> // 如果传入是 function 说明是只读 computed if (isFunction(getterOrOptions)) { getter = getterOrOptions setter = __DEV__ ? () => { console.warn(Write operation failed: computed value is readonly) } : NOOP } else { // 不是方法说明是自定义的 getter setter getter = getterOrOptions.get setter = getterOrOptions.set } let dirty = true let value: T let computed: ComputedRef<T> // 创建 effect, 我们在看 effect 源码时知道了传入 lazy 代表不会立即执行,computed 表明 computed 上游依赖改变的时候,会优先 trigger runner effect, scheduler 表示 effect trigger 的时候会调用 scheduler 而不是直接调用 effect const runner = effect(getter, { lazy: true, // mark effect as computed so that it gets priority during trigger computed: true, scheduler: () => { // 在触发更新时把dirty置为true, 不会立即更新 if (!dirty) { dirty = true trigger(computed, TriggerOpTypes.SET, value) } } }) // 构造一个 computed 返回 computed = { __v_isRef: true, // expose effect so computed can be stopped effect: runner, get value() { // dirty为ture, get操作时,执行effect获取最新值 // if (dirty) { value = runner() dirty = false } // dirty为false, 表示值未更新,直接返回 track(computed, TrackOpTypes.GET, value) return value }, set value(newValue: T) { setter(newValue) } } as any return computed }computed计算属性有两个特点:
延时计算:只有当我们访问计算属性时,真正运行computed getter函数计算 缓存:它的内部会缓存上次的计算结果value,而只有dirty为true时才会重新计算,如果访问计算属性时dirty为false,那么直接返回这个value那么,计算属性的优势是:只要依赖不变化,就可以使用缓存的value而不用每次再渲染组件的时候都执行函数去计算。
做个嵌套计算的小例子,我们看到:对于addOne而言,云服务器提供商它收集的依赖是组件副作用渲染函数,而对于count而言,它收集的依赖是addTwo内部的runner函数。当我们修改count值,会进行派发通知,先运行addOne中的setter函数,此时addOne中的dirty值变成true,然后trigger函数再次派发通知;接着运行addTwo中的setter函数,此时把addTwo中的dirty值设置为true;当我们再次访问addTwo中的值时,发现dirty值为true,就会执行addTwo的computed函数,会先去执行addOne.value + 1,再去执行addOne的computed函数中的count.value + 1。这样就得到最后打印出来的值为2。
const count = ref(0); const addOne = computed(()=>{ return count.value + 1;//1 }) const addTwo = computed(()=>{ return addOne.value + 1;//2 }) console.log(addTwo.value);//2得益于computed计算属性的巧妙设计,无论嵌套多少层都能够正常运行。
import { ref,computed} from "vue"; import { effect} from "@vue/reactivity"; const count = ref(0); const addOne = computed(()=>{ return count.value + 1; }) effect(()=>console.log(addOne.value+count.value)) function add(){ count.value++; } add();我们看到上面代码最终输出结果是:1 3 3
当我们第一次执行addOne的香港云服务器computed计算属性时,count.value值还是0,而addOne.value的值为1,将会触发并执行effect,此时打印出来还是1。而后执行add()函数,会进行修改count.value的值,会触发并执行effect函数,因为addOne也是effect的依赖,addOne的runners函数也是count.value的依赖,count.value值的修改会执行runners函数,会再次执行addOne的依赖,接着会触发effect函数,因此会输出两次3。
computed函数返回的对象实际上劫持的是value属性的getter和setter,但是为什么我们在组件的模板中访问一个计算属性变量,不用手动在后面加.value呢?
参考文章
《Vue3核心源码解析》 《Vue中文社区》 《Vue3中文文档》写在最后
理解计算属性的工作机制,能够搞明白计算属性嵌套场景代码的执行顺序,知道计算属性的两个特点--延时计算和缓存,在组件的开发中合理使用计算属性。
很赞哦!(64)
相关文章
- 域后缀首选.com,.net,然后是.cn。后缀选择不当,导致流量损失。域名是企业与互联网网址之间的链接,关键是企业在网络上存在的标志。因此,选择好域名是开展网上工作的首要重要条件。
- 这就是所谓的JavaScript异步!
- 基于OpenResty的单机10万TPS网关在物流业务中的应用
- 深入源码分析Java线程池的实现原理
- .com域名是国际最广泛流行的通用域名,目前全球注册量第一的域名,公司企业注册域名的首选。国际化公司通常会注册该类域名。
- GitHub上6个热门Java开源项目推荐
- 编程语言的巅峰境界
- 为什么学完了C语言,我只会写计算机程序?
- 在数以亿计的网站中,我们应该抓住每一个可能带来宣传的机会,域名可以带有企业的名字,一般可以使用汉语拼音或者英语单词或者是相关缩写的形式,只要用户记住了你企业的名字,就能很容易的打出你的网站域名,同样的,记住了网站域名也能很快的记住你公司的名字。
- 腾讯在职8年Python开发经验的程序员写给初学者的总结,希望有用