免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
閱完此文,Vue響應(yīng)式不再話下

vue的雙向數(shù)據(jù)綁定,眾所周知是基于Object.defineProperty這個(gè)在瀏覽器的特性api來(lái)實(shí)現(xiàn)的。但是怎么從視圖到數(shù)據(jù),數(shù)據(jù)到視圖,這個(gè)整個(gè)大過(guò)程,對(duì)于很多盆友來(lái)說(shuō),還有點(diǎn)不是很清楚。

這篇文章,將會(huì)特別輕松的換個(gè)角度讓你明白整個(gè)過(guò)程。just do it !!! ??????


Vue的響應(yīng)式系統(tǒng)

我們第一次使用Vue的時(shí)候,會(huì)感覺(jué)有些神奇,舉個(gè)例子:
<div id='app'>  <div>價(jià)格:¥{{price}}</div>  <div>總價(jià):¥{{price*quantity}}</div>  <div>折扣后:¥{{totlePriceWithTax}}</div></div><script>  var vm=new Vue({    el:'#app',    data:(){      price:5.00,//單價(jià)      quantity:2//數(shù)量    },    computed:{       totlePriceWithTax(){          return this.price*this.quantity*1.03        }    }  })</script>
我們使用vue的時(shí)候,不知道它內(nèi)部做了什么。它都能知道price這個(gè)字段的值是否發(fā)生過(guò)變化,如果發(fā)生了變化,他會(huì)做如下幾件事:
  • 更新頁(yè)面顯示的price的值

  • 重新計(jì)算總價(jià)的乘法表達(dá)式并且更新顯示結(jié)果

  • 重新調(diào)用totlePriceWithTax函數(shù),并且更新顯示

這兒,咱們就有一個(gè)疑問(wèn),vue怎么就知道price變化了之后,都要更新哪些值呢?為什么,每次一變化,就要更新呢?如何跟蹤的呢?
JavaScript正常的運(yùn)行方式
我們把這個(gè)例子整理成我們正常的JavaScript程序來(lái)看看:
let price=5;let quantity=2;let total=price*quantity;//計(jì)算總價(jià)pice=20;//price字段發(fā)生變更之后console.log(`變化之后的總價(jià):${total}`);
這個(gè)會(huì)輸出打印多少呢?因?yàn)槲疫@兒沒(méi)有使用Vue,很明顯,這兒會(huì)輸出10:
>> 變化之后的總價(jià):10
在咱們經(jīng)常使用的Vue中,我們想要在price或者quantity這兩個(gè)字段更新時(shí),和它有關(guān)的表達(dá)式也會(huì)更新,和它有關(guān)的函數(shù)也會(huì)執(zhí)行。
>> 變化之后的總價(jià):40
但是,javascript是過(guò)程性的,不是響應(yīng)式的,所以這個(gè)代碼在實(shí)際運(yùn)行的時(shí)候是不行的。為了讓total在price更新的時(shí)候,它也跟著更新,我們必須讓JavaScript語(yǔ)言具備不同的運(yùn)行方式。
問(wèn)題
那么我們現(xiàn)在就遇到了一個(gè)問(wèn)題,怎么樣,才能在price字段或者quantity更新的時(shí)候,total也重新更新顯示呢?
嘗試一下
首先,我們需要明白price和totle的關(guān)聯(lián)是:
let total=price*quantity;
那么,在price更新之后,需要重新得到新的total,就需要重新執(zhí)行這個(gè)方法。那么就需要有一個(gè)地方把這個(gè)方法儲(chǔ)存起來(lái),在price變更的時(shí)候,重新運(yùn)行儲(chǔ)存起來(lái)的方法,這樣total值就更新了。
那我們就來(lái)嘗試一下,把函數(shù)記錄下來(lái),后面變更的時(shí)候,再次運(yùn)行。
let price=5;let quantity=2;let total=0;let target=null;//記錄函數(shù)target=()=>{  total=price*quantity;}record();//后面講解,記住這個(gè)我們后面想要運(yùn)行的函數(shù)target();//同時(shí),我們執(zhí)行一遍這個(gè)方法
record記錄函數(shù)的實(shí)現(xiàn)就很簡(jiǎn)單了:
let storage=[];//這是要記錄函數(shù)的地方,就是上面圖中橢圓的那個(gè)東西//記錄方法的實(shí)現(xiàn),這個(gè)時(shí)候的target就是我們要記錄的方法function record(){  storage.push(target)}
這一步,將target儲(chǔ)存了起來(lái),這樣我們后面就可以運(yùn)行它。這個(gè)時(shí)候,我們就需要一個(gè)運(yùn)行所有記錄的內(nèi)容的函數(shù)。那我們就來(lái)搞一哈:
function replay(){  storage.forEach((run)=>{    run();  })}
這兒,我們遍歷了所有記錄的內(nèi)容,并且每一個(gè)都執(zhí)行。
這個(gè)時(shí)候,我們的代碼就可以更改一下:
let price=5;let quantity=2;let total=0;let target=null;
function record(){ storage.push(target)}
function replay(){ storage.forEach((run)=>{ run(); })}
target=()=>{ total=price*quantity;}record();target();
console.log(total)// 10price=20;replay();console.log(total)//40
這樣我們就實(shí)現(xiàn)了,一個(gè)記錄的過(guò)程,但是這樣沒(méi)有一個(gè)很好地管理,我們能不能把記錄這塊的內(nèi)容,維護(hù)成一個(gè)類,讓這個(gè)類維護(hù)一個(gè)tagert列表,每次需要重新運(yùn)行的時(shí)候,這個(gè)類都會(huì)得到通知。
年輕人,火力旺,說(shuō)干就干。維護(hù)一個(gè)單獨(dú)的Dep類,代碼如下:
class Dep{ constructor(){ this.subscribers=[];//維護(hù)所有target的列表,在得到通知的時(shí)候,全部都會(huì)運(yùn)行 } depend(){ if(target&&!this.subscribers.includes(target)){ //只有target有方法,并且沒(méi)有被記錄過(guò) this.subscribers.push(target); } } notify(){ this.subscribers.forEach((sub)=>{ sub(); }) }}
在這個(gè)類中,我們不再使用storage,使用subscribers這個(gè)字符來(lái)記錄target函數(shù)的內(nèi)容,也不再使用record,使用depend,也用了notify替代了replay,這個(gè)時(shí)候要運(yùn)行,就只需要:
const dep=new Dep();
let price=5;let quantity=2;let total=0;let target=null;
target=()=>{ total=price*quantity;}dep.depend();//記錄到subscribers中target();
console.log(total)// 10price=20;dep.notify();//遍歷執(zhí)行所有target,分發(fā)內(nèi)容console.log(total)//40
這樣,整體的過(guò)程就會(huì)好一點(diǎn),但是還是會(huì)顯得很冗余,如果能過(guò)把匿名函數(shù)創(chuàng)建,觀察,更新的這些行為封裝起來(lái),那就更好了。
年輕人,總是沖動(dòng),咱們說(shuō)干就干。把原來(lái)的創(chuàng)建和記錄:
target=()=>{ total=price*quantity;}dep.depend();//記錄到subscribers中target();
這塊內(nèi)容封裝起來(lái),咱們給封裝起來(lái)的函數(shù)起名叫做watcher,封裝起來(lái)之后,我們就只需要這樣調(diào)用:
watcher(()=>{ total=price*quantity})
那我們?cè)趯?shí)現(xiàn)watcher的時(shí)候,這么做就好:
function watcher(myFunc){ target=myFunc;//傳入的函數(shù)賦值 dep.depend();//收集 target();//執(zhí)行一下 target=null;//重置}
這兒,咱們看到watcher函數(shù)接受了一個(gè)變量myFunc,這個(gè)myFunc后面接收的是匿名函數(shù),然后賦值給target屬性,調(diào)用dep.depend(),將以訂閱者的形式添加target到記錄的地方,然后調(diào)用target,并且重置。
現(xiàn)在結(jié)合上面的代碼咱們嘗試一下這個(gè)代碼:
price=20;console.log(total);dep.notify();console.log(total);
這里面有一個(gè)問(wèn)題,就是target為什么要設(shè)置成全局變量,而不是將其傳遞給需要的函數(shù)。咱們后面會(huì)細(xì)聊。
現(xiàn)在我們有一個(gè)Dep類了,但是我們整整想要實(shí)現(xiàn)的情況是,每一個(gè)變量都有響應(yīng)的地方記錄它關(guān)聯(lián)的變更,每個(gè)變量都有自己的Dep。這個(gè)可咋整?
年輕人,不怕事,說(shuō)干就干。咱們首先把所有的變量放到一起:
let data={ price:5, quantity:2}
現(xiàn)在我們假設(shè)每一個(gè)屬性(price和quantity)都有自己內(nèi)部的Dep類。
當(dāng)我們運(yùn)行watcher這個(gè)函數(shù)的時(shí)候:
wacther(()=>{ total=data.price*data.quantity})
因?yàn)槲覀兪鞘褂玫搅薲ata.price的值,那么我們希望price屬性的Dep類可以將使用它的匿名函數(shù)(儲(chǔ)存在target上)放在訂閱數(shù)組中,記錄下來(lái)(通過(guò)調(diào)用dep.depend())。同時(shí)data.quantity這個(gè)變量也被訪問(wèn)了,所以也希望能夠被記錄下來(lái),放在對(duì)應(yīng)的訂閱數(shù)組中:
如果這個(gè)時(shí)候還有其他的地方也在使用data.price,我們也希望可以把對(duì)應(yīng)的匿名函數(shù)放到Dep類中記錄下來(lái)。
那么,什么時(shí)候會(huì)調(diào)用price對(duì)應(yīng)的Dep中的notify呢?在price賦值,值發(fā)生改變的時(shí)候。我們最后希望發(fā)生的效果是:
>> total10>> price=20>> total40
我們希望,當(dāng)數(shù)據(jù)被訪問(wèn)的時(shí)候,能夠把對(duì)應(yīng)的target匿名函數(shù)儲(chǔ)存到訂閱數(shù)組中,當(dāng)屬性變更的時(shí)候,能夠運(yùn)行對(duì)應(yīng)的儲(chǔ)存在訂閱數(shù)組中的匿名函數(shù)。
解決方案
這個(gè)一眼看過(guò)去,訪問(wèn)時(shí),改變時(shí)。腦海中直接就出來(lái)了Object.defineProperty,這個(gè)允許我們?yōu)閷傩远xgetter和setter函數(shù)。在展示如何和Dep結(jié)合的之前,先看下用法:
let data={price:5,quantity:2};Object.defineProperty(data,'price',{ get(){ console.log('被訪問(wèn)') }, set(newVal){ console.log('被修改') }});data.price;//輸出:被訪問(wèn)data.price=20;//輸出:被修改
這里,我們并沒(méi)有實(shí)際的修改get和set的值,因?yàn)楣δ鼙桓采w了?,F(xiàn)在,我們希望get的時(shí)候能夠返回一個(gè)值,set的時(shí)候能夠更新值。所以我們先添加一個(gè)變量internalValue來(lái)儲(chǔ)存當(dāng)前的price的值。
let data={price:5,quantity:2};
let internalValue=data.price;//初始值
Object.defineProperty(data,'price',{ get(){ console.log('被訪問(wèn)'); return internalValue }, set(newVal){ console.log('被修改'); internalValue=newVal }});total=data.price*data.quantity;//調(diào)用getdata.price=20;//調(diào)用set
這樣我們就可以把所有我們想要的監(jiān)聽的數(shù)據(jù),全部給處理一下:
let data={price:5,quantity:2};
Object.keys(data).forEach((key)=>{ let internalValue=data[key];//初始值
Object.defineProperty(data,key,{ get(){ console.log('被訪問(wèn)'); return internalValue }, set(newVal){ console.log('被修改'); internalValue=newVal } });})
total=data.price*data.quantity;//調(diào)用getdata.price=20;//調(diào)用set
這樣所有的數(shù)據(jù)都變了可監(jiān)聽的了。
把他們結(jié)合起來(lái)
total=data.price*data.quantity
當(dāng)這個(gè)代碼運(yùn)行的時(shí)候,會(huì)觸發(fā)price屬性對(duì)應(yīng)的get方法,我們希望price的Dep可以記住這個(gè)對(duì)應(yīng)的匿名函數(shù)(target)。通過(guò)這個(gè)方式,如果發(fā)生改變,觸發(fā)了set,那么就能夠調(diào)用這個(gè)屬性對(duì)應(yīng)的儲(chǔ)存起來(lái)的匿名函數(shù)。
  • Get—記住匿名函數(shù),當(dāng)值發(fā)生變化的時(shí)候重新運(yùn)行。

  • Set—運(yùn)行保存的匿名函數(shù),對(duì)應(yīng)匿名函數(shù)綁定的值就會(huì)發(fā)生變化

切換到Dep class的模式:
  • price被訪問(wèn)時(shí)—調(diào)用dep.depend保存當(dāng)前target

  • price被改變時(shí)—調(diào)用price的dep.notify,重新運(yùn)行所有的target

最后,我們就把這個(gè)結(jié)合起來(lái),年輕人,不要磨磨蹭蹭,突突兩下就可以了:
let data={price:5,quantity:2};let target=null;class Dep{ constructor(){ this.subscribers=[];//維護(hù)所有target的列表,在得到通知的時(shí)候,全部都會(huì)運(yùn)行 } depend(){ if(target&&!this.subscribers.includes(target)){ //只有target有方法,并且沒(méi)有被記錄過(guò) this.subscribers.push(target); } } notify(){ this.subscribers.forEach((sub)=>{ sub(); }) }}Object.keys(data).forEach((key)=>{  let internalValue=data[key];//初始值 Object.defineProperty(data,key,{ get(){ console.log('被訪問(wèn)'); dep.depend();//添加對(duì)應(yīng)的匿名函數(shù)target return internalValue }, set(newVal){ console.log('被修改'); internalValue=newVal; dep.notify();//觸發(fā)對(duì)應(yīng)的儲(chǔ)存的函數(shù) } });})function watcher(myFunc){ target=myFunc;//傳入的函數(shù)賦值 target();//執(zhí)行一下 target=null;//重置}watcher(()=>{ data.total=data.price*data.quantity;})
這就結(jié)合了這一塊的東西,price和quantity兩個(gè)屬性變成了響應(yīng)式的情況,可以下來(lái)試一下。
直接上架構(gòu)圖:
最后,Vue2中還有很多東西,Vue3也出來(lái)了,我們這塊出了對(duì)應(yīng)的課程。年輕人不要猶猶豫豫。機(jī)會(huì)和成長(zhǎng)總在猶豫的時(shí)候就溜走了。
在這樣一個(gè)信息爆炸、知識(shí)唾手可得的時(shí)代,年輕人一定要做個(gè)明白人,懂得篩選和判斷優(yōu)質(zhì)內(nèi)容。
你可能經(jīng)常會(huì)領(lǐng)取到海量前端資料包,收藏起來(lái)就再也沒(méi)看過(guò)。
但今天,我們想給你點(diǎn)真正有品質(zhì)的內(nèi)容——【你不知道的Vue.js 性能優(yōu)化】
  • 本次專題課深度講解 Vue.js 性能優(yōu)化,以及 Vue3.0 那些值得關(guān)注的新特性。在高級(jí)前端崗位面試中,性能優(yōu)化是一個(gè)必問(wèn)的知識(shí)點(diǎn),本課程通過(guò)對(duì) Vue 面試核心知識(shí)點(diǎn)的拆解,帶你解鎖你可能不知道的 Vue.js 性能優(yōu)化,直達(dá)大廠offer!

它將帶你學(xué)到什么?
1.Vue首屏優(yōu)化實(shí)踐
  • 大廠面試問(wèn)Vue項(xiàng)目?jī)?yōu)化時(shí)的各種講解

  • 核心工程化知識(shí)點(diǎn)講解

  • 不同的核心優(yōu)化方案剖析

  • ??糣ue知識(shí)點(diǎn)串講

2.面試常問(wèn)的Vue雙向數(shù)據(jù)深度解析
  • 修正對(duì)于Object.defineProperty的錯(cuò)誤理解

  • Vue2中雙向數(shù)據(jù)綁定為什么性能不好?

  • 數(shù)組的雙向數(shù)據(jù)綁定怎么處理的

3.深度對(duì)比 Vue2 & 3,助你直達(dá)offer
  • 淺嘗Vue3的使用

  • Vue3的新特性解析

  • Vue3核心雙向數(shù)據(jù)綁定的實(shí)現(xiàn)解析

  • 深度對(duì)比Vue2,助你直達(dá)offer

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Vue 進(jìn)階系列之響應(yīng)式原理及實(shí)現(xiàn)
vue2.0源碼分析之理解響應(yīng)式架構(gòu)
手摸手帶你理解Vue響應(yīng)式原理
如何寫出整潔的代碼——技巧與最佳實(shí)踐
【前端開發(fā)】】2019年前端面試常用知識(shí)點(diǎn)總結(jié)
TypeScript 筆記小結(jié)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服