awesome-interview/book1/frame-vue-computed-watch.html

21 lines
22 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-book1/frame-vue-computed-watch">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v2.3.1">
<title data-rh="true">Vue 的 computed 和 watch 的区别 | HZFE - 剑指前端 Offer</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://febook.hzfe.org/awesome-interview/book1/frame-vue-computed-watch"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Vue 的 computed 和 watch 的区别 | HZFE - 剑指前端 Offer"><meta data-rh="true" name="description" content="相关问题"><meta data-rh="true" property="og:description" content="相关问题"><link data-rh="true" rel="icon" href="/awesome-interview/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://febook.hzfe.org/awesome-interview/book1/frame-vue-computed-watch"><link data-rh="true" rel="alternate" href="https://febook.hzfe.org/awesome-interview/book1/frame-vue-computed-watch" hreflang="en"><link data-rh="true" rel="alternate" href="https://febook.hzfe.org/awesome-interview/book1/frame-vue-computed-watch" hreflang="x-default"><link data-rh="true" rel="preconnect" href="https://PED5MQGL7T-dsn.algolia.net" crossorigin="anonymous"><link rel="search" type="application/opensearchdescription+xml" title="HZFE - 剑指前端 Offer" href="/awesome-interview/opensearch.xml">
<link rel="manifest" href="/awesome-interview/manifest.json">
<link rel="preconnect" href="https://hm.baidu.com">
<script>var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="https://hm.baidu.com/hm.js?c7cd0fd77ac518cc6ef46461cdc9524b";var c=document.getElementsByTagName("script")[0];c.parentNode.insertBefore(e,c)}()</script>
<script src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" async data-ad-client="ca-pub-9889934432771967"></script>
<script src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9889934432771967" async crossorigin="anonymous"></script><link rel="stylesheet" href="/awesome-interview/assets/css/styles.0f62048e.css">
<link rel="preload" href="/awesome-interview/assets/js/runtime~main.a05aa7a0.js" as="script">
<link rel="preload" href="/awesome-interview/assets/js/main.55789724.js" as="script">
</head>
<body class="navigation-with-keyboard">
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="navbar navbar--fixed-top navbarHideable_m1mJ"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/awesome-interview/"><div class="navbar__logo"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_ToTc themedImage--light_HNdA"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_ToTc themedImage--dark_i4oU"></div><b class="navbar__title text--truncate">剑指前端 Offer</b></a></div><div class="navbar__items navbar__items--right"><a href="https://github.com/hzfe/awesome-interview" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a><div class="searchBox_ZlJk"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg width="20" height="20" class="DocSearch-Search-Icon" viewBox="0 0 20 20"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"></span></button></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="docusaurus_skipToContent_fallback" class="main-wrapper mainWrapper_z2l0 docsWrapper_BCFX"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docPage__5DB"><aside class="theme-doc-sidebar-container docSidebarContainer_b6E3"><div class="sidebarViewport_Xe31"><div class="sidebar_njMd sidebarWithHideableNavbar_wUlq"><a tabindex="-1" class="sidebarLogo_isFc" href="/awesome-interview/"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_ToTc themedImage--light_HNdA"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_ToTc themedImage--dark_i4oU"><b>剑指前端 Offer</b></a><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/awesome-interview/about">关于我们</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/awesome-interview/">前言</a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" aria-expanded="true" href="/awesome-interview/book1/browser-cross-origin">模拟题一</a></div><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/browser-cross-origin">浏览器:浏览器跨域</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/browser-repain-reflow">浏览器:浏览器的重排重绘</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/engineer-webpack-workflow">工程化webpack 工作流程</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/frame-vue-data-binding">框架Vue 的数据绑定机制</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/awesome-interview/book1/frame-vue-computed-watch">框架Vue 的 computed 和 watch 的区别</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/js-closures">基础:闭包的作用和原理</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/js-module-specs">基础:前端模块化规范</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/css-bfc">样式BFC 的形成和作用</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/network-security">网络:前端安全</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/coding-promise">编码:实现一个符合 Promises/A+ 规范的 Promise</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/algorithm-balanced-binary-trees">算法:平衡二叉树</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/topic-enter-url-display-xx">综合:浏览器从输入网址到页面展现的过程</a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/awesome-interview/book2/browser-render-mechanism">模拟题二</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/awesome-interview/book3/browser-event-loop">模拟题三</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/awesome-interview/book4/browser-router">模拟题四</a></div></li></ul></nav><button type="button" title="Collapse sidebar" aria-label="Collapse sidebar" class="button button--secondary button--outline collapseSidebarButton_PEFL"><svg width="20" height="20" aria-hidden="true" class="collapseSidebarButtonIcon_kv0_"><g fill="#7a7a7a"><path d="M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"></path><path d="M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"></path></g></svg></button></div></div></aside><main class="docMainContainer_gTbr"><div class="container padding-top--md padding-bottom--lg"><button class="chatbox-button">Answer Bot</button><div class="row"><div class="col docItemCol_VOVn"><div class="docItemContainer_Djhp"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_Z_bl" aria-label="Breadcrumbs"><ul class="breadcrumbs" itemscope="" itemtype="https://schema.org/BreadcrumbList"><li class="breadcrumbs__item"><a aria-label="Home page" class="breadcrumbs__link" href="/awesome-interview/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_YNFT"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li class="breadcrumbs__item"><span class="breadcrumbs__link">模拟题一</span><meta itemprop="position" content="1"></li><li itemscope="" itemprop="itemListElement" itemtype="https://schema.org/ListItem" class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link" itemprop="name">框架Vue 的 computed 和 watch 的区别</span><meta itemprop="position" content="2"></li></ul></nav><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_TO0P">On this page</button></div><div class="theme-doc-markdown markdown"><h1>Vue 的 computed 和 watch 的区别</h1><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="相关问题">相关问题<a href="#相关问题" class="hash-link" aria-label="Direct link to 相关问题" title="Direct link to 相关问题"></a></h2><ul><li>computed 和 watch 的实现原理</li><li>computed 和 watch 的适用场景</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="回答关键点">回答关键点<a href="#回答关键点" class="hash-link" aria-label="Direct link to 回答关键点" title="Direct link to 回答关键点"></a></h2><p><code>响应变化</code> <code>属性</code> <code>侦听</code></p><p>computed 是模板表达式的声明式描述,会<strong>创建新的响应式数据</strong>。而 watch 是响应式数据的<strong>自定义侦听器</strong>,用于<strong>响应数据的变化</strong>。除此之外computed 还具有<strong>可缓存可依赖多个属性getter 函数无副作用</strong>等特点。watch 则更适用于<strong>异步或开销大的操作</strong></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="知识点深入">知识点深入<a href="#知识点深入" class="hash-link" aria-label="Direct link to 知识点深入" title="Direct link to 知识点深入"></a></h2><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="1-实现原理">1. 实现原理<a href="#1-实现原理" class="hash-link" aria-label="Direct link to 1. 实现原理" title="Direct link to 1. 实现原理"></a></h3><p>在了解 Vue 数据双向绑定的基础上computed 等同于为属性设置 <strong>getter 函数</strong>(也可设置 <a href="https://cn.vuejs.org/v2/guide/computed.html#%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7%E7%9A%84-setter" target="_blank" rel="noopener noreferrer">setter</a>),而 watch 等同于为属性的 <strong>setter 设置回调函数、监听深度 deep 及响应速度 immediate</strong>。下面简单讲解下两者的实现原理,具体细节可以参考<a href="https://github.com/vuejs/vue" target="_blank" rel="noopener noreferrer">源码</a></p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="11-computed-原理">1.1 computed 原理<a href="#11-computed-原理" class="hash-link" aria-label="Direct link to 1.1 computed 原理" title="Direct link to 1.1 computed 原理"></a></h4><p>主要分为四个阶段</p><p><img loading="lazy" src="https://user-images.githubusercontent.com/12165373/125889331-b97687a3-2037-4bb9-9d4e-8405f5ed271f.png" alt="computed四个阶段" class="img_ev3q"></p><ol><li><strong>初始化</strong>:为 computed 属性创建 lazy watcher此处 watcher 指双向绑定中的监听器,下同)。</li><li><strong>首次模板渲染</strong>:渲染 watcher 检测到 computed 属性时,会调用 computed 属性的 getter 方法,而 computed 属性的 getter 方法会调用依赖属性的 getter从而形成链式调用同时保存引用关系用于更新。取得计算结果后 lazy watcher 会将结果缓存,并返回给渲染 watcher 进行模板渲染。</li><li><strong>多次模板渲染</strong>:直接取 lazy watcher 中的缓存值给到渲染 watcher 进行渲染。</li><li><strong>依赖属性更新</strong>:根据首次模板渲染阶段构建的依赖关系向上通知 lazy watcher 进行重新计算,缓存计算结果并通知渲染 watcher 重新渲染更新页面。</li></ol><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="12-watch-原理">1.2 watch 原理<a href="#12-watch-原理" class="hash-link" aria-label="Direct link to 1.2 watch 原理" title="Direct link to 1.2 watch 原理"></a></h4><p>watch 本质上是为每个监听属性 setter 创建了一个 watcher当被监听的属性更新时调用传入的回调函数。常见的配置选项有 deep 和 immediate对应原理如下</p><ol><li><strong>deep</strong>:深度监听对象,为对象的每一个属性创建一个 watcher从而确保对象的每一个属性更新时都会触发传入的回调函数。主要原因在于对象属于引用类型单个属性的更新并不会触发对象 setter因此引入 deep 能够很好地解决监听对象的问题。同时也会引入判断机制,确保在多个属性更新时回调函数仅触发一次,避免性能浪费。</li><li><strong>immediate</strong>:在初始化时直接调用回调函数,可以通过在 created 阶段手动调用回调函数实现相同的效果。</li></ol><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="2-适用场景">2. 适用场景<a href="#2-适用场景" class="hash-link" aria-label="Direct link to 2. 适用场景" title="Direct link to 2. 适用场景"></a></h3><ul><li>computed需要处理复杂逻辑的模板表达式。</li><li>watch需要执行异步或开销较大的操作。</li></ul><p>从表现上看computed 会创建<strong>新的属性</strong>,而 watch 可以通过<strong>将属性设置在 data 中,再监听依赖属性变化,调用 handler 方法更新属性</strong>的方式达到同样的效果。因此不难得出 computed 的使用场景可以被 watch 覆盖这一结论。但在具体的使用上还是优先考虑 computed因为相同场景下 watch 所需的代码量和性能开销一般来说会比 computed 大,具体可以参照 <a href="https://cn.vuejs.org/v2/guide/computed.html#%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7-vs-%E4%BE%A6%E5%90%AC%E5%B1%9E%E6%80%A7" target="_blank" rel="noopener noreferrer">computed vs watched</a>。在 computed 无法满足需求的情况下再考虑使用 watch也可以有效避免 watch 滥用,提升性能。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="3-vue3-与-vue2-区别">3. Vue3 与 Vue2 区别<a href="#3-vue3-与-vue2-区别" class="hash-link" aria-label="Direct link to 3. Vue3 与 Vue2 区别" title="Direct link to 3. Vue3 与 Vue2 区别"></a></h3><p><strong>Vue3 中 computed 和 watch 的原理以及在 Options API 中的使用方式和 Vue2 保持一致。但在 Vue3 的新特性组合式CompositionAPI 中,使用方式和功能相比 Vue2 有了明显差别</strong>。使用方式由原来在组件中声明改为直接从 Vue 中导入使用,各自的调用方式和参数也发生了改变,功能更加多样,同时 Vue3 还引入了 watchEffect 作为 watch 的补充,以求用更简洁的代码来覆盖更广的使用场景。具体使用参考<a href="https://v3.cn.vuejs.org/guide/reactivity-computed-watchers.html" target="_blank" rel="noopener noreferrer">官方文档</a></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="参考资料">参考资料<a href="#参考资料" class="hash-link" aria-label="Direct link to 参考资料" title="Direct link to 参考资料"></a></h2><ol><li><a href="https://cn.vuejs.org/v2/guide/computed.html" target="_blank" rel="noopener noreferrer">Vuejs computed</a></li><li><a href="https://github.com/vuejs/vue" target="_blank" rel="noopener noreferrer">Vuejs 源码</a></li><li><a href="https://v3.cn.vuejs.org/guide/composition-api-introduction.html" target="_blank" rel="noopener noreferrer">Vue3 组合式 api</a></li></ol></div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages navigation"><a class="pagination-nav__link pagination-nav__link--prev" href="/awesome-interview/book1/frame-vue-data-binding"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">框架Vue 的数据绑定机制</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/awesome-interview/book1/js-closures"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">基础:闭包的作用和原理</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#相关问题" class="table-of-contents__link toc-highlight">相关问题</a></li><li><a href="#回答关键点" class="table-of-contents__link toc-highlight">回答关键点</a></li><li><a href="#知识点深入" class="table-of-contents__link toc-highlight">知识点深入</a><ul><li><a href="#1-实现原理" class="table-of-contents__link toc-highlight">1. 实现原理</a><ul><li><a href="#11-computed-原理" class="table-of-contents__link toc-highlight">1.1 computed 原理</a></li><li><a href="#12-watch-原理" class="table-of-contents__link toc-highlight">1.2 watch 原理</a></li></ul></li><li><a href="#2-适用场景" class="table-of-contents__link toc-highlight">2. 适用场景</a></li><li><a href="#3-vue3-与-vue2-区别" class="table-of-contents__link toc-highlight">3. Vue3 与 Vue2 区别</a></li></ul></li><li><a href="#参考资料" class="table-of-contents__link toc-highlight">参考资料</a></li></ul></div></div></div><div class="row"><div class="col"><div class="react-utterences"><div>Loading script...</div></div></div><div class="col col--3"></div><div class="chatbox-container" style="height:0"><div style="flex-grow:1;padding:0 10%"><iframe src="https://interview-book-ai.hzfe.org" height="100%" width="100%"></iframe></div></div></div></div></main></div></div></div>
<script src="/awesome-interview/assets/js/runtime~main.a05aa7a0.js"></script>
<script src="/awesome-interview/assets/js/main.55789724.js"></script>
</body>
</html>