<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
前言:
目前工作中大概有 的需求是在用 的技術棧,所謂知其然更要知其所以然,為了更好的使用 、更快的排查問題,最近學習了原始碼相關的一些知識,雖然網上總結 的很多很多了,不少自己一個,但也不多自己一個,歡迎一起討論學習,發現問題歡迎指出。40%
Vue2
Vue
Vue
回到最簡單的程式碼:
data = { text: 'hello, world' } const updateComponent = () => { console.log('收到', data.text); } updateComponent() data.text = 'hello, liang' // 執行結果 // 收到 hello, world
響應式系統要做的事情:某個依賴了 資料的函數,當所依賴的 資料改變的時候,該函數要重新執行。data
data
我們期望的效果:當上邊 修改的時候, 函數再執行一次。data.text
updateComponent
為了實現響應式系統,我們需要做兩件事情:
data
data
中的資料改變的時候去呼叫依賴它的函數們為了實現第 點,我們需要在執行函數的時候,將當前函數儲存起來,然後在讀取資料的時候將該函數儲存到當前資料中。1
第 點就迎刃而解了,當修改資料的時候將儲存起來的函數執行一次即可。2
在讀取資料和修改資料的時候需要做額外的事情,我們可以通過 重寫物件屬性的 和 函數。Object.defineProperty()
get
set
我們來寫一個函數,重寫屬性的 和 函數。get
set
/** * Define a reactive property on an Object. */ export function defineReactive(obj, key, val) { const property = Object.getOwnPropertyDescriptor(obj, key); // 讀取使用者可能自己定義了的 get、set const getter = property && property.get; const setter = property && property.set; // val 沒有傳進來話進行手動賦值 if ((!getter || setter) && arguments.length === 2) { val = obj[key]; } Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { const value = getter ? getter.call(obj) : val; /*********************************************/ // 1.這裡需要去儲存當前在執行的函數 /*********************************************/ return value; }, set: function reactiveSetter(newVal) { const value = getter ? getter.call(obj) : val; if (setter) { setter.call(obj, newVal); } else { val = newVal; } /*********************************************/ // 2.將依賴當前資料依賴的函數執行 /*********************************************/ }, }); }
為了呼叫更方便,我們把第 步和第 步的操作封裝一個 類。1
2
Dep
export default class Dep { static target; //當前在執行的函數 subs; // 依賴的函數 constructor() { this.subs = []; // 儲存所有需要執行的函數 } addSub(sub) { this.subs.push(sub); } depend() { // 觸發 get 的時候走到這裡 if (Dep.target) { // 委託給 Dep.target 去呼叫 addSub Dep.target.addDep(this); } } notify() { for (let i = 0, l = this.subs.length; i < l; i++) { this.subs[i].update(); } } } Dep.target = null; // 靜態變數,全域性唯一
我們將當前執行的函數儲存到 類的 變數上。Dep
target
為了儲存當前的函數,我們還需要寫一個 類,將需要執行的函數傳入,儲存到 類中的 屬性中,然後交由 類負責執行。Watcher
Watcher
getter
Watcher
這樣在 類中, 中儲存的就不是當前函數了,而是持有當前函數的 物件。Dep
subs
Watcher
import Dep from "./dep"; export default class Watcher { constructor(Fn) { this.getter = Fn; this.get(); } /** * Evaluate the getter, and re-collect dependencies. */ get() { Dep.target = this; // 儲存包裝了當前正在執行的函數的 Watcher let value; try { // 呼叫當前傳進來的函數,觸發物件屬性的 get value = this.getter.call(); } catch (e) { throw e; } return value; } /** * Add a dependency to this directive. */ addDep(dep) { // 觸發 get 後會走到這裡,收集當前依賴 // 當前正在執行的函數的 Watcher 儲存到 dep 中的 subs 中 dep.addSub(this); } /** * Subscriber interface. * Will be called when a dependency changes. */ // 修改物件屬性值的時候觸發 set,走到這裡 update() { this.run(); } /** * Scheduler job interface. * Will be called by the scheduler. */ run() { this.get(); } }
Watcher
的作用就是將正在執行的函數通過 包裝後儲存到 中,然後呼叫傳進來的函數,此時觸發物件屬性的 函數,會收集當前 。Watcher
Dep.target
get
Watcher
如果未來修改物件屬性的值,會觸發物件屬性的 ,接著就會呼叫之前收集到的 物件,通過 物件的 方法,來呼叫最初執行的函數。set
Watcher
Watcher
uptate
回到我們之前沒寫完的 函數,按照上邊的思路,我們來補全一下。defineReactive
import Dep from "./dep"; /** * Define a reactive property on an Object. */ export function defineReactive(obj, key, val) { const property = Object.getOwnPropertyDescriptor(obj, key); // 讀取使用者可能自己定義了的 get、set const getter = property && property.get; const setter = property && property.set; // val 沒有傳進來話進行手動賦值 if ((!getter || setter) && arguments.length === 2) { val = obj[key]; } /*********************************************/ const dep = new Dep(); // 持有一個 Dep 物件,用來儲存所有依賴於該變數的 Watcher /*********************************************/ Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { const value = getter ? getter.call(obj) : val; /*********************************************/ // 1.這裡需要去儲存當前在執行的函數 if (Dep.target) { dep.depend(); } /*********************************************/ return value; }, set: function reactiveSetter(newVal) { const value = getter ? getter.call(obj) : val; if (setter) { setter.call(obj, newVal); } else { val = newVal; } /*********************************************/ // 2.將依賴當前資料依賴的函數執行 dep.notify(); /*********************************************/ }, }); }
我們再寫一個 方法,把物件的全部屬性都變成響應式的。Observer
export class Observer { constructor(value) { this.walk(value); } /** * 遍歷物件所有的屬性,呼叫 defineReactive * 攔截物件屬性的 get 和 set 方法 */ walk(obj) { const keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]); } } }
我們提供一個 方法來負責建立 物件。observe
Observer
export function observe(value) { let ob = new Observer(value); return ob; }
將上邊的方法引入到文章最開頭的例子,來執行一下:
import { observe } from "./reactive"; import Watcher from "./watcher"; const data = { text: "hello, world", }; // 將資料變成響應式的 observe(data); const updateComponent = () => { console.log("收到", data.text); }; // 當前函數由 Watcher 進行執行 new Watcher(updateComponent); data.text = "hello, liang";
此時就會輸出兩次了~
收到 hello, world
收到 hello, liang
說明我們的響應式系統成功了。
先從整體理解了響應式系統的整個流程:
每個屬性有一個 陣列, 會持有當前執行的函數,當讀取屬性的時候觸發 ,將當前 儲存到 陣列中,當屬性值修改的時候,再通過 陣列中的 物件執行之前儲存的函數。subs
Watcher
get
Watcher
subs
subs
Watcher
到此這篇關於Vue2響應式系統介紹的文章就介紹到這了,更多相關Vue2響應式系統內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45