awesome-interview/book1/frame-vue-data-binding.html

29 lines
58 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="Docusaurus v2.0.0-beta.5">
<link rel="search" type="application/opensearchdescription+xml" title="HZFE - 剑指前端 Offer" href="/awesome-interview/opensearch.xml">
<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><title data-react-helmet="true">Vue 的数据绑定机制 | HZFE - 剑指前端 Offer</title><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" property="og:url" content="https://febook.hzfe.org/awesome-interview/book1/frame-vue-data-binding"><meta data-react-helmet="true" name="docsearch:language" content="en"><meta data-react-helmet="true" name="docsearch:version" content="current"><meta data-react-helmet="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-react-helmet="true" property="og:title" content="Vue 的数据绑定机制 | HZFE - 剑指前端 Offer"><meta data-react-helmet="true" name="description" content="相关问题"><meta data-react-helmet="true" property="og:description" content="相关问题"><link data-react-helmet="true" rel="shortcut icon" href="/awesome-interview/img/favicon.ico"><link data-react-helmet="true" rel="canonical" href="https://febook.hzfe.org/awesome-interview/book1/frame-vue-data-binding"><link data-react-helmet="true" rel="alternate" href="https://febook.hzfe.org/awesome-interview/book1/frame-vue-data-binding" hreflang="en"><link data-react-helmet="true" rel="alternate" href="https://febook.hzfe.org/awesome-interview/book1/frame-vue-data-binding" hreflang="x-default"><link data-react-helmet="true" rel="preconnect" href="https://BH4D9OD16A-dsn.algolia.net" crossorigin="anonymous"><link rel="stylesheet" href="/awesome-interview/assets/css/styles.304d13b7.css">
<link rel="preload" href="/awesome-interview/assets/js/runtime~main.e4536af0.js" as="script">
<link rel="preload" href="/awesome-interview/assets/js/main.52f9823f.js" as="script">
</head>
<body>
<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><a href="#" class="skipToContent_1oUP">Skip to main content</a></div><nav class="navbar navbar--fixed-top navbarHideable_2qcr"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Navigation bar toggle" class="navbar__toggle clean-btn" type="button" tabindex="0"><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/"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_1VuW themedImage--light_3UqQ navbar__logo"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_1VuW themedImage--dark_hz6m navbar__logo"><b class="navbar__title">剑指前端 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"><span>GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_3J9K"><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></span></a><div class="searchBox_1Doo"><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 class="main-wrapper docs-wrapper docs-doc-page"><div class="docPage_31aa"><button class="clean-btn backToTopButton_35hR" type="button"><svg viewBox="0 0 24 24" width="28"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" fill="currentColor"></path></svg></button><aside class="docSidebarContainer_3Kbt"><div class="sidebar_15mo sidebarWithHideableNavbar_267A"><a tabindex="-1" class="sidebarLogo_3h0W" href="/awesome-interview/"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_1VuW themedImage--light_3UqQ"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_1VuW themedImage--dark_hz6m"><b>剑指前端 Offer</b></a><nav class="menu thin-scrollbar menu_Bmed menuWithAnnouncementBar_2WvA"><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" href="/awesome-interview/about">关于我们</a></li><li class="menu__list-item"><a class="menu__link" href="/awesome-interview/">前言</a></li><li class="menu__list-item"><a class="menu__link menu__link--sublist menu__link--active" href="#">模拟题一</a><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/browser-cross-origin">浏览器:浏览器跨域</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/browser-repain-reflow">浏览器:浏览器的重排重绘</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/engineer-webpack-workflow">工程化Webpack 工作流程</a></li><li class="menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/awesome-interview/book1/frame-vue-data-binding">框架Vue 的数据绑定机制</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/frame-vue-computed-watch">框架Vue 的 computed 和 watch 的区别</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/js-closures">基础:闭包的作用和原理</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/js-module-specs">基础:前端模块化规范</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/css-bfc">样式BFC 的形成和作用</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/network-security">网络:前端安全</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/coding-promise">编码:实现一个 Promises/A+</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/algorithm-balanced-binary-trees">算法:平衡二叉树</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book1/topic-enter-url-display-xx">综合:浏览器从输入网址到页面展现的过程</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#">模拟题二</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#">模拟题三</a></li></ul></nav><button type="button" title="Collapse sidebar" aria-label="Collapse sidebar" class="button button--secondary button--outline collapseSidebarButton_1CGd"><svg width="20" height="20" aria-hidden="true" class="collapseSidebarButtonIcon_3E-R"><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></aside><main class="docMainContainer_3ufF"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_3FnS"><div class="docItemContainer_33ec"><article><div class="tocCollapsible_1PrD tocMobile_3Hoh"><button type="button" class="clean-btn tocCollapsibleButton_2O1e">On this page</button></div><div class="markdown"><header><h1>Vue 的数据绑定机制</h1></header><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithHideOnScrollNavbar_3R7-" id="相关问题"></a>相关问题<a class="hash-link" href="#相关问题" title="Direct link to heading">#</a></h2><ul><li>Vue 是如何实现数据劫持的</li><li>Vue 是如何实现双向绑定的</li><li>MVVM 是什么</li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithHideOnScrollNavbar_3R7-" id="回答关键点"></a>回答关键点<a class="hash-link" href="#回答关键点" title="Direct link to heading">#</a></h2><p><code>响应式对象</code> <code>数据劫持</code> <code>双向绑定</code> <code>MVVMModel-View-ViewModel</code> <code>发布/订阅模式publish-subscribe pattern</code></p><p><strong>响应式对象</strong></p><p>Vue2 通过 <code>Object.defineProperty</code>Vue3 通过 Proxy 来劫持 state 中各个属性的 setter、getter通过 getter 收集依赖。当 state 中的数据发生变动之后发布通知给订阅者更新数据。</p><p><strong>双向绑定</strong></p><p>Vue 通过 <code>v-model</code> 实现双向绑定。<code>v-model</code> 实际是 <code>v-bind:xxx</code><code>v-on:xxx</code> 的语法糖。当触发元素对应的事件(如 input、change 等时更新数据ViewModel当数据ViewModel更新时同步更新到元素的对应属性View上。</p><p><strong>MVVMModel-View-ViewModel</strong></p><p>MVVM 模式是一种软件架构模式,相比 MVC 模式多了一个 ViewModel 层。有助于将图形用户界面的开发与业务逻辑或后端逻辑(数据模型)的开发分离开来。</p><ul><li>Model模型层负责处理业务逻辑以及和服务器端进行交互。</li><li>View视图层将数据通过 UI 展现出来。</li><li>ViewModel视图模型层连接 Model 层和 View 层。</li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithHideOnScrollNavbar_3R7-" id="知识点深入"></a>知识点深入<a class="hash-link" href="#知识点深入" title="Direct link to heading">#</a></h2><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithHideOnScrollNavbar_3R7-" id="1-前置概念"></a>1. 前置概念<a class="hash-link" href="#1-前置概念" title="Direct link to heading">#</a></h3><p>在详细说明原理之前,需要对以下概念有一定的认知:</p><ol><li>Dep实现发布订阅模式的模块。</li><li>Watcher订阅更新和触发视图更新的模块。</li></ol><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithHideOnScrollNavbar_3R7-" id="2-实现原理"></a>2. 实现原理<a class="hash-link" href="#2-实现原理" title="Direct link to heading">#</a></h3><p><img src="https://user-images.githubusercontent.com/3984824/132991936-828bba61-2c87-4ee2-acf0-ffef294760fb.png" alt="image"></p><p>上图是 Vue 官网描述 Vue 内数据变化与发布更新的流程,我们以响应式对象、依赖收集、数据更新的顺序详细说明整个过程。</p><h4><a aria-hidden="true" tabindex="-1" class="anchor anchor__h4 anchorWithHideOnScrollNavbar_3R7-" id="21-响应式对象"></a>2.1 响应式对象<a class="hash-link" href="#21-响应式对象" title="Direct link to heading">#</a></h4><p>Vue2 通过 <code>Object.defineProperty</code>Vue3 通过 Proxy 来劫持 state 中各个属性的 getter、setter。其中 getter 中主要是通过 Dep 收集依赖这个属性的订阅者setter 中则是在属性变化后通知 Dep 收集到的订阅者,派发更新。</p><p>以下是 Dep 的伪代码:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly typescript"><pre tabindex="0" class="prism-code language-typescript codeBlock_23N8 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name maybe-class-name">Dep</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> target</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">Watcher</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> subs</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Array</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">Watcher</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">constructor</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">subs</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 添加订阅者watcher</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> **/</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">addSub</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sub</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">Watcher</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">subs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sub</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 移除订阅者watcher</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> **/</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">removeSub</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sub</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">Watcher</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">subs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sub</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 添加订阅(调用订阅者上的 addDep 方法)</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> **/</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">depend</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token maybe-class-name">Dep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token maybe-class-name">Dep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addDep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 遍历通知订阅者更新</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> **/</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">notify</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> subs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">subs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">slice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> l </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> l</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> subs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">update</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token maybe-class-name">Dep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">target</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p>以下是生成响应式对象的伪代码:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly typescript"><pre tabindex="0" class="prism-code language-typescript codeBlock_23N8 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 生成响应式对象</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 为了方便理解,以下代码略有修改,省略了部分不相关内容</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">defineReactive</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> obj</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> dep </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name maybe-class-name">Dep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">defineProperty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">obj</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> enumerable</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> configurable</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">get</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">reactiveGetter</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 每次 get 时如果有订阅者则添加订阅</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token maybe-class-name">Dep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> dep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">depend</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> val</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">set</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">reactiveSetter</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">newVal</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> val </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> newVal</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 每次更新数据之后广播更新</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> dep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">notify</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><h4><a aria-hidden="true" tabindex="-1" class="anchor anchor__h4 anchorWithHideOnScrollNavbar_3R7-" id="22-依赖收集"></a>2.2 依赖收集<a class="hash-link" href="#22-依赖收集" title="Direct link to heading">#</a></h4><p>Vue 会在需要使用到属性的地方新建一个 Watcher 的实例 watcherwatcher 实例化时会读取对应属性的内容,从而触发 1.1 中的 getter将 watcher 注册进 Dep 中。</p><p>以下是 Watcher 的伪代码:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly typescript"><pre tabindex="0" class="prism-code language-typescript codeBlock_23N8 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 为了方便理解,以下代码略有修改,省略了部分不相关内容</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name maybe-class-name">Watcher</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> vm</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">Component</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> getter</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> cb</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">constructor</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> vm</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">Component</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> exp</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">vm</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> vm</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">cb</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cb</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 获取表达式对应的属性的 getter</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">getter</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">parsePath</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">exp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">value</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 获取最新的值</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> **/</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 将 Dep 的当前订阅者指向当前 watcher</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token maybe-class-name">Dep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">target</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> value</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> vm </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">vm</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 获取对应属性值</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getter</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">vm</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> vm</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 清空 Dep 当前订阅者</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token maybe-class-name">Dep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">target</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> value</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 订阅</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> **/</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">addDep</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dep</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">Dep</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 将当前 watcher 添加到 Dep 的订阅者列表中</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> dep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addSub</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 更新视图</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> **/</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">update</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> oldValue </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">value</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 调用 callback 更新视图</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">cb</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">vm</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> oldValue</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><h4><a aria-hidden="true" tabindex="-1" class="anchor anchor__h4 anchorWithHideOnScrollNavbar_3R7-" id="23-数据更新"></a>2.3 数据更新<a class="hash-link" href="#23-数据更新" title="Direct link to heading">#</a></h4><p>state 属性更新时会触发属性的 settersetter 中会触发 Dep 的更新Dep 通知 1.2 中收集到的 watcher 更新watcher 获取到更新的数据之后触发更新视图。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithHideOnScrollNavbar_3R7-" id="3-无法监听到的变化"></a>3. 无法监听到的变化<a class="hash-link" href="#3-无法监听到的变化" title="Direct link to heading">#</a></h3><p>由于受到 JavaScript 设计的限制Vue2 使用的 <code>Object.defineProperty</code> 并不能完全劫持所有数据的变化,以下是几种无法正常劫持的变化:</p><ul><li>无法劫持新创建的属性为了解决这个问题Vue 提供了 <code>Vue.set</code> 以创建新属性。</li><li>无法劫持数组的变化为了解决这个问题Vue 对数组原生方法进行了劫持。</li><li>无法劫持利用索引修改数组元素,这个问题同样可以用 <code>Vue.set</code> 解决。</li></ul><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithHideOnScrollNavbar_3R7-" id="4-vue2-与-vue3-的差异"></a>4. Vue2 与 Vue3 的差异<a class="hash-link" href="#4-vue2-与-vue3-的差异" title="Direct link to heading">#</a></h3><p>Vue2 与 Vue3 数据绑定机制的主要差异是劫持方式。Vue2 使用的是 <code>Object.defineProperty</code> 而 Vue3 使用的是 <code>Proxy</code><code>Proxy</code> 可以创建一个对象的代理,从而实现对这个对象基本操作的拦截和自定义。</p><table><thead><tr><th>特性</th><th>defineProperty</th><th>Proxy</th></tr></thead><tbody><tr><td>劫持新创建属性</td><td></td><td></td></tr><tr><td>劫持数组变化</td><td></td><td></td></tr><tr><td>劫持索引修改数组元素</td><td></td><td></td></tr><tr><td>兼容性</td><td>IE8及以上</td><td>不支持IE</td></tr></tbody></table><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithHideOnScrollNavbar_3R7-" id="参考资料"></a>参考资料<a class="hash-link" href="#参考资料" title="Direct link to heading">#</a></h2><ol><li><a href="https://vuejs.org/" target="_blank" rel="noopener noreferrer">Vuejs 官网</a></li><li><a href="https://github.com/vuejs/vue" target="_blank" rel="noopener noreferrer">Vuejs 源码</a></li></ol></div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages navigation"><div class="pagination-nav__item"><a class="pagination-nav__link" href="/awesome-interview/book1/engineer-webpack-workflow"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">« 工程化Webpack 工作流程</div></a></div><div class="pagination-nav__item pagination-nav__item--next"><a class="pagination-nav__link" href="/awesome-interview/book1/frame-vue-computed-watch"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">框架Vue 的 computed 和 watch 的区别 »</div></a></div></nav></div></div><div class="col col--3"><div class="tableOfContents_35-E thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#相关问题" class="table-of-contents__link">相关问题</a></li><li><a href="#回答关键点" class="table-of-contents__link">回答关键点</a></li><li><a href="#知识点深入" class="table-of-contents__link">知识点深入</a><ul><li><a href="#1-前置概念" class="table-of-contents__link">1. 前置概念</a></li><li><a href="#2-实现原理" class="table-of-contents__link">2. 实现原理</a></li><li><a href="#3-无法监听到的变化" class="table-of-contents__link">3. 无法监听到的变化</a></li><li><a href="#4-vue2-与-vue3-的差异" class="table-of-contents__link">4. Vue2 与 Vue3 的差异</a></li></ul></li><li><a href="#参考资料" class="table-of-contents__link">参考资料</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></div></main></div></div></div>
<script src="/awesome-interview/assets/js/runtime~main.e4536af0.js"></script>
<script src="/awesome-interview/assets/js/main.52f9823f.js"></script>
</body>
</html>