<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
前言
相信vue學習者都會發現,vue使用起來上手非常方便,例如雙向繫結機制,讓我們實現檢視、資料層的快速同步,但雙向繫結機制實現的核心資料響應的原理是怎麼樣的呢,接下來讓我們開始介紹:
function observer(value) { //給所有傳入進來的data 設定一個__ob__物件 一旦value有__ob__ 說明該value已經做了響應式處理 Object.defineProperty(value, '__ob__', { value: this, //當前範例 也就是new observer enumerable: false, //不可列舉 即不可for in writable: true, // 可用賦值運運算元改寫__ob__ configurable: true //可改寫可刪除 }) //這裡是判斷是物件 陣列的話需要改造陣列原型上的方法 if (Object.prototype.toString.call(value) === "[object Array]") { //陣列的話需要改造陣列原型上的方法 下面會講解arrayMethods value.__proto__ = arrayMethods; //對陣列進行響應式處理 observeArray(value); } else { //如果是物件 遍歷物件屬性進行響應式處理 iterate(value) } } // 遍歷物件屬性進行響應式處理 function iterate(data) { const keys = Object.keys(data); keys.forEach((key) => { defineReactive(data, key, data[key]) }) } //響應式處理 這裡是核心 function defineReactive(data, key, value){ //遞迴物件 這裡是因為物件裡面仍可能巢狀物件 observe(value) //寫道這裡 Object.defineProperty 我們主角出場了 // 這裡實現了讀寫都能捕捉到,響應式的底層原理 Object.defineProperty(data, key, { get() { console.log('我被成功存取啦!'); return value }, set(newValue) { if (newValue === value) return console.log("我被變更啦") value = newValue } }) } function observeArray(data) { data.forEach(item => { observe(item) }) } function observe(value) { // 如果傳進來的是物件或者陣列,則進行響應式處理 if (Object.prototype.toString.call(value) === '[object Object]' || Object.prototype.toString.call(value) === "[object Array]") { return new Observer(value) } }
上面程式碼簡單的實現了vue2.0中響應式的原理,相信註釋也非常的清晰,總結一下三個主要的方法:
名稱 | 作用 |
---|---|
observer | 觀察者物件,對陣列、物件進行響應式處理 |
defineReactive | 攔截物件中的key中的set、get方法 |
observe | 響應式處理的入口 |
從上面的大致實現方法中,我們不難看出幾個問題:
1.使用defineProperty,我們無法實現物件刪除的監聽、以及新增物件屬性的時候,set方法沒有被呼叫,下圖是實驗結果
2.陣列修改只能通過改寫的方法,無法通過arr[index] = xxx 進行修改,也無法通過length屬性進行修改,下圖是輸出結果:
解決方案
針對上面的問題,vue提出了自己的解決方案:
$set(obj, key, value)
,原理相信大家不難猜出,通過hack的方式,物件的處理方法是重新為物件賦值,而陣列是通過splice來轉換為響應式
function set (target, key, val) { //isValidArrayIndex 用來檢測是否合法索引 if (Array.isArray(target) && isValidArrayIndex(key)) { target.length = Math.max(target.length, key); target.splice(key, 1, val); return val } if (key in target && !(key in Object.prototype)) { target[key] = val; return val } //... defineReactive$$1(ob.value, key, val); ob.dep.notify(); return val }
陣列的特殊處理
相信大家還發現,陣列做了特殊處理,上面的程式碼也寫到沒有使用遍歷使用defineProperty去監聽資料,修改陣列原型上的部分方法,來實現修改陣列觸發響應式,也就是上面程式碼的arrayMethods
,我們接著來看這個的具體實現思路:
const arrayProto = Array.prototype export const arrayMethods = Object.create(arrayProto) const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] methodsToPatch.forEach(method =>{ // 快取原來的方法 def(arrayMethods, method) }) function def(obj, key) { Object.defineProperties(obj, key, { enumerable: true, configurable: true, value: function (...args) { //獲取陣列原生方法 let original = arrayProto[key]; //改變this指向 const result = original.apply(this, args) console.log('我被更新了'); //result就是上文的arrayMethods return result; } }) }
這裡大概分為三個思路
1.獲取陣列原型上的方法
2.使用defineProperties對陣列原型上的方法進行劫持
3.把需要被改造的 Array 原型方法指向改造後原型。
這樣做的好處
沒有直接修改 Array.prototype,而是直接把 arrayMenthods 賦值給 value 的 proto 。因為這樣不會汙染全域性的Array, arrayMenthods 只對 data中的Array 生效。
題外話
關於陣列為什麼不使用defineProperties進行劫持,網上大部分說法都是覺得開銷太大,因為在我們業務場景中一般的物件不會有太多屬性,但列表中幾千、上萬條資料確是很正常,這一點也可以講通。
感謝你的閱讀,在vue3.0中使用proxy進行資料劫持後,都說解決了2.0存在的問題以及提升了效率,後面我也會完善3.0響應式的實現原理。
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注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