21 lines
22 KiB
HTML
21 lines
22 KiB
HTML
<!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 的新特性组合式(Composition)API 中,使用方式和功能相比 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> |