ref函數(shù)
語(yǔ)法:
復(fù)制const xxx=ref(initValue)
接受的數(shù)據(jù)類型:基本類型,對(duì)象類型
作用:
把參數(shù)加工成一個(gè)響應(yīng)式對(duì)象,全稱為reference對(duì)象(我們下面一律簡(jiǎn)稱為ref對(duì)象)
核心原理:
響應(yīng)式依賴Object.defineProperty()的get()和set()。
Ref函數(shù)對(duì)于基本數(shù)據(jù)類型的參數(shù)
基本使用:
復(fù)制?
{{Str}}
import {ref} from 'vue'export default {? setup(){? ? const Str =ref('hello')? ? return{? ? ? Str? ? }? }}上面我們定義了一個(gè)Str變量來(lái)接收ref加工生成的ref對(duì)象,我們都知道對(duì)象的數(shù)據(jù)都是以鍵值對(duì)的形式存儲(chǔ)的,但是在這里為什么直接把Str給return出去, 并且模板里可以直接寫(xiě)Str這個(gè)對(duì)象呢,我們的源數(shù)據(jù)呢?帶著這個(gè)疑問(wèn)我們來(lái)輸出一下Str:
復(fù)制setup(){? ? const Str =ref('hello')? ? console.log(Str)? ? return{? ? ? Str? ? }}
打印結(jié)果如下:
復(fù)制RefImpl__v_isRef: true_rawValue: "hello"_shallow: false_value: "hello"value: "hello"[[Prototype]]: Object
在這里我們看到了ref對(duì)象身上的一個(gè)屬性?value,沒(méi)錯(cuò),我們存入的值就對(duì)應(yīng)在value屬性上,至于為什么直接return出是Str而不是Str.value。是因?yàn)閂ue幫了我們一個(gè)忙,我們?cè)谶@里可以簡(jiǎn)寫(xiě),return出去的Str就相當(dāng)于Str.value,當(dāng)然,非要寫(xiě).value的形式也不是不可以。不過(guò)這里需要注意的是,在setup函數(shù)中操作Str中的數(shù)據(jù)不可以簡(jiǎn)寫(xiě)。
響應(yīng)式原理:
對(duì)于基本數(shù)據(jù)類型說(shuō)完了它的基本用法,下面我們來(lái)說(shuō)說(shuō)他的響應(yīng)式原理,也就是我們?yōu)槭裁捶且靡粋€(gè)ref對(duì)象來(lái)接受數(shù)據(jù),而不是直接就定義好一個(gè)字符串'hello',然后去直接操作這個(gè)字符串?
對(duì)于ref函數(shù),數(shù)據(jù)參數(shù)和它加工生成的ref對(duì)象二者存在著某種“契約”,我們把加工好的參數(shù)也就是ref對(duì)象交出去之后,我們直接操作修改的就是ref對(duì)象上的value屬性,因?yàn)檫@個(gè)契約的存在,以至于在修改屬性值的時(shí)候?qū)?yīng)的源數(shù)據(jù)參數(shù)也會(huì)連同被修改,但在原數(shù)據(jù)被修改之前vue就會(huì)監(jiān)聽(tīng)到我們修改了數(shù)據(jù),立馬進(jìn)行解析模板更新頁(yè)面,這就是ref對(duì)象的響應(yīng)式原理。這里的契約其實(shí)就是Object.defineProperty的get()和set(),篇幅有限我們不對(duì)底層核心代碼做示范.
我們知道了ref函數(shù)定義基本類型,下面會(huì)講解reactive函數(shù),該函數(shù)參數(shù)是對(duì)象類型和ref的對(duì)象類型參數(shù)有著千絲萬(wàn)縷的聯(lián)系,所以學(xué)會(huì)reactive函數(shù)學(xué)會(huì)了ref函數(shù)存儲(chǔ)的對(duì)象數(shù)據(jù)類型也就自然理解了。
reactive函數(shù)
語(yǔ)法:
復(fù)制const xxx=ref(源對(duì)象)
接受的數(shù)據(jù)類型:對(duì)象類型
作用:
把參數(shù)加工成一個(gè)代理對(duì)象,全稱為proxy對(duì)象
核心原理:
基于Es6的Proxy實(shí)現(xiàn),通過(guò)代理操作源對(duì)象,相比于reactive定義的淺層次響應(yīng)式數(shù)據(jù)對(duì)象,reactive定義的是更深層次的響應(yīng)式數(shù)據(jù)對(duì)象。
reactive對(duì)于對(duì)象類型的參數(shù)
基本使用:
復(fù)制?
姓名:{{Person.name}}
?薪水:{{Person.job.salary}}
import {reactive} from 'vue'export default {? setup(){? ? const p ={? ? ? name:'Ben',? ? ? job:{? ? ? ? salary:'30k'? ? ? }? ? }? ? const Person =reactive(p)? ? return{? ? ? Person? ? }? }}這里不同于上面的ref函數(shù),參數(shù)是一個(gè)對(duì)象類型的數(shù)據(jù),那么對(duì)于接受返回值的Person對(duì)象也會(huì)和上面的ref對(duì)象一樣都是把數(shù)據(jù)對(duì)應(yīng)到value屬性上嗎?帶著這個(gè)疑問(wèn)打印一下Person對(duì)象:
復(fù)制Proxy[[Handler]]: Object[[Target]]: Objectjob: {salary: "30k"}name: "Ben"[[Prototype]]: Object[[IsRevoked]]: false
我們發(fā)現(xiàn)Person對(duì)象身上并沒(méi)有value屬性并且Person對(duì)象是一個(gè)proxy類型的對(duì)象,這里我們可以理解為Person是一個(gè)加強(qiáng)版的p對(duì)象,對(duì)于p來(lái)說(shuō)Person是一個(gè)代理對(duì)象,所以我們可以直接訪問(wèn)到自身的屬性,而不是和ref函數(shù)一樣把數(shù)據(jù)對(duì)應(yīng)到value屬性上,所以我們r(jià)eturn出去的Person對(duì)象可以直接放在模板里讀取屬性。
響應(yīng)式原理:
reactive的響應(yīng)式是更加“深層次”的,底層依賴于ES6中的Proxy實(shí)現(xiàn),用reactive函數(shù)加工出來(lái)的對(duì)象都是Proxy對(duì)象,無(wú)論原數(shù)據(jù)對(duì)象里面有多少層對(duì)象他們都會(huì)被加工成Proxy類型對(duì)象(深層次)。它的響應(yīng)式核心思想和ref是大同小異的,這里我們定義的Person對(duì)象來(lái)代理p對(duì)象,二者也會(huì)建立“契約”,我們?cè)诎裀erson對(duì)象return出去后,在我們操作修改Person對(duì)象的數(shù)據(jù)時(shí),在原對(duì)象數(shù)據(jù)改變之前Vue都會(huì)監(jiān)聽(tīng)到這一舉動(dòng)并且同時(shí)解析模板、更新頁(yè)面。
Ref函數(shù)對(duì)于對(duì)象類型的參數(shù)
說(shuō)到這里大家會(huì)有個(gè)疑問(wèn),ref定義對(duì)象類型的數(shù)據(jù)和這個(gè)reactive函數(shù)有什么關(guān)系呢?
ref對(duì)象只能去操作淺層次的數(shù)據(jù),把基本數(shù)據(jù)類型當(dāng)做自己的屬性值,如果ref函數(shù)的參數(shù)是對(duì)象這種深層次的數(shù)據(jù)類型時(shí)它會(huì)求助一個(gè)人,這個(gè)人不是別人正是reactive函數(shù),在底層Vue會(huì)把對(duì)象參數(shù)通過(guò)reactive函數(shù)加工成一個(gè)Proxy代理對(duì)象放到ref的value屬性上。
復(fù)制?
姓名:{{Person.name}}
?薪水:{{Person.job.salary}}
import {reactive,ref} from 'vue'export default {? setup(){? ? const p ={? ? ? name:'Ben',? ? ? job:{? ? ? ? salary:'30k'? ? ? }? ? }? ? const Person =ref(p)? ? console.log(Person)? ? return{? ? ? Person? ? }? }}打印Person對(duì)象的結(jié)果:
復(fù)制RefImpl {_shallow: false, __v_isRef: true, _rawValue: {…}, _value: Proxy}__v_isRef: true_rawValue: {name: "Ben", job: {…}}_shallow: false_value: Proxy {name: "Ben", job: {…}}value: Proxy[[Handler]]: Object[[Target]]: Objectjob: {salary: "30k"}name: "Ben"[[Prototype]]: Object[[IsRevoked]]: false[[Prototype]]: Object
我們可以很清楚的看到,value屬性下對(duì)應(yīng)的正是給p原數(shù)據(jù)對(duì)象加工生成Proxy對(duì)象。
區(qū)別
存儲(chǔ)類型:ref對(duì)象可以接受基本數(shù)據(jù)類型得數(shù)據(jù)也可以接受對(duì)象類型的數(shù)據(jù),而reactive只可以接受對(duì)象類型的數(shù)據(jù);
響應(yīng)式:相比于ref對(duì)象reactive函數(shù)是更深層次的,ref函數(shù)參數(shù)為對(duì)象類型時(shí)依賴的也是reactive函數(shù);
用法:Proxy代理對(duì)象的數(shù)據(jù)鍵值對(duì)是和原數(shù)據(jù)對(duì)象的鍵值對(duì)一一對(duì)應(yīng)的,在使用時(shí)可以直接使用 對(duì)象(接受返回值的對(duì)象).鍵名 的形式,ref對(duì)象會(huì)把數(shù)據(jù)參數(shù)對(duì)應(yīng)到自己;
value屬性上,在模板里我們可以直接省略.value的形式,這看起來(lái)好像是“把源數(shù)據(jù)賦值給了ref類型的變量,可以直接在模板上使用這個(gè)ref類型的變量”;
響應(yīng)式原理:ref的響應(yīng)式原理是依賴于Object.defineProperty()的get()和set()而reactive的響應(yīng)式原理是依賴于ES6中的Proxy。