tip:本系列博客的代码部分(示例等除外),均出自vue源码内容,版本为2.6.14。但是为了增加易读性,会对不相关内容做选择性省略。如果大家想了解完整的源码,建议自行从官方下载。
【VUE】源码分析 - computed计算属性的实现原理_依然范特西fantasy的博客-优快云博客
【VUE】源码分析 - watch侦听器的实现原理_依然范特西fantasy的博客-优快云博客
【VUE】源码分析 - 数据劫持的基本原理_依然范特西fantasy的博客-优快云博客
前言
在分析computed属性之前,我们已经介绍过了数据劫持的基本原理、侦听器的基本原理。而computed属性或多或少与它们存在某些联系。实现原理本质上,依旧是一个收集依赖,触发依赖的过程。本篇博客假设你对数据劫持充分了解,对Watcher类有了初步的认识。如果你对这些还不太熟悉,建议戳上方链接,学习前置知识后再来阅读本文。
步入正题
来自官方文档的介绍:在模板中放入太多的逻辑会让模板过重且难以维护。对于任何复杂逻辑,你都应当使用计算属性。
简单来说,就是模板语法中应该只关注结果,而不应该存在过多的逻辑。如果某些地方牵涉到过多过复杂的逻辑,那么就应该使用计算属性,将相关逻辑存放在其中,而模板中只需要使用此计算属性即可。
我们知道,在模板中使用响应式数据,那么当这些响应式数据发生改变的时候,就会通知到相应的模板节点,从而重新渲染最新的结果,展示到页面上。
那如果使用的是计算属性computed,它又是如何实现监听到相关数据的变化的呢?在多处地方使用同一个计算属性,它是否会触发多次逻辑运算呢?而这些,就是在本章需要讨论的内容。
computed的初始化
先来看computed的初始化函数:
const computedWatcherOptions = { lazy: true }
function initComputed(vm, computed) {
const watchers = (vm._computedWatchers = Object.create(null));
for (const key in computed) {
const userDef = computed[key];
const getter = typeof userDef === "function" ? userDef : userDef.get;
if (process.env.NODE_ENV !== "production" && getter == null) {
warn(`Getter is missing for computed property "${key}".`, vm);
}
watchers[key] = new Watcher(
vm,
getter || noop,
noop,