欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue3為什么要用proxy替代defineProperty

 更新時(shí)間:2020年10月19日 11:45:08   作者:_洋羽  
這篇文章主要介紹了vue3為什么要用proxy替代defineProperty,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在這之前,我們得先了解下vue的核心理念mutable

不管是vue2還是vue3,在實(shí)現(xiàn)的過程中,核心概念一直保持穩(wěn)定,以可變數(shù)據(jù)源為核心的理念,來實(shí)現(xiàn)整個(gè)UI變動(dòng)更新

用最簡(jiǎn)單的講法就是:初始化數(shù)據(jù)生成了頁面,直接修改源數(shù)據(jù)觸發(fā)更新,頁面重新渲染

關(guān)注vue的人都知道,vue3里面使用了proxy替換了defineProperty,

在使用vue2的時(shí)候,我們經(jīng)常會(huì)碰到一個(gè)問題,添加新的對(duì)象屬性obj.a = 1會(huì)無法被vue2劫持,必須使用vue2提供的$set方法來進(jìn)行更新

這個(gè)的原因想必大家也都清楚,因?yàn)閐efineProperty只能對(duì)當(dāng)前對(duì)象的其中一個(gè)屬性進(jìn)行劫持

const a = {
  b: 1,
};
Object.defineProperty(a, 'b', {
  set: function() {},
  get: function() {},
});

當(dāng)我們給a對(duì)象新增一個(gè)屬性的時(shí)候,當(dāng)前新增的屬性并沒有被defineProperty劫持,雖然在對(duì)應(yīng)的對(duì)象上依舊成功的生成了一個(gè)新的屬性,但是我們知道,vue2是通過defineProperty的setter與getter進(jìn)行數(shù)據(jù)劫持的,既然新增的數(shù)據(jù)并沒有被劫持,所以無論怎么更新,頁面依舊不會(huì)重新渲染

而在vue3中,使用proxy來進(jìn)行數(shù)據(jù)代理就完全沒有這個(gè)顧慮了

const p = new Proxy({
  a: 1,
  b: 2,
}, {
  get: function(obj, value) {
    console.log('get', obj, value);
    return Reflect.get(obj, value);
  },
  set: function(obj, prop, value) {
    console.log('set', obj, prop, value);
    return Reflect.set(obj, prop, value);
  },
})

proxy對(duì)于數(shù)據(jù)的代理,是能夠響應(yīng)新增的屬性,當(dāng)新增一個(gè)屬性的時(shí)候,可以響應(yīng)到get中,對(duì)當(dāng)前對(duì)象進(jìn)行代理

vue3是如何通過proxy代理的

首先可以看下vue3新增的幾個(gè)主要apiref, reactive, effect,computed

ref和reactive
const normal = ref(0);
const state = reactive({
  a: 1,
  b: 2,
})

vue3中對(duì)vue2的兼容處理也是使用了reactive,即instance.data = reactive(data),將整個(gè)data屬性使用reactive進(jìn)行代理

我們知道,vue2中的data就是使用Object.definePerproty進(jìn)行數(shù)據(jù)劫持的, 那么在reactive中,他是如何使用proxy進(jìn)行數(shù)據(jù)代理的,來兼容老的書寫方式與新的compositionApi

ps: 由于在reactive里面也只是通過proxy對(duì)傳入的數(shù)據(jù)校驗(yàn)和代理,最主要的還是set和get,所以我們還是直接上壘吧,畢竟心急吃得了熱豆腐

get

可以分析一下,vue2也好,vue3也罷,針對(duì)于數(shù)據(jù)的獲取所做的事情主要內(nèi)容不會(huì)有什么區(qū)別

  1. 獲取當(dāng)前需要的key的數(shù)據(jù)
  2. 依賴采集

但是,針對(duì)于vue3使用proxy的特性,在這邊額外做了一部分的兼容

  1. 如果獲取的數(shù)據(jù)是一個(gè)對(duì)象,則會(huì)對(duì)對(duì)象再使用reactive進(jìn)行一次數(shù)據(jù)的代理
  2. 如果是shallow類型的數(shù)據(jù)代理, 則直接返回當(dāng)前獲取到的數(shù)據(jù)

effect依賴采集

vue除去正常的data的數(shù)據(jù)代理以外,還有對(duì)應(yīng)的computed和watch,而在vue3中直接使用了watchEffect和computed方法能夠直接生成對(duì)應(yīng)的內(nèi)容

他們的數(shù)據(jù)更新和依賴處理都是依托于當(dāng)前data數(shù)據(jù)上的get進(jìn)行依賴的收集

掐頭去尾的來看最核心的代碼

// targetMap當(dāng)前所有代理的數(shù)據(jù)的一個(gè)Map集合
// depsMap當(dāng)前代理的數(shù)據(jù)的每一個(gè)Key所對(duì)應(yīng)的Map集合
// dep當(dāng)前代理的數(shù)據(jù)中的key的對(duì)應(yīng)依賴
// activeEffect當(dāng)前由effect或者computed生成的數(shù)據(jù)

let depsMap = targetMap.get(target)
if (!depsMap) {
  targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
  depsMap.set(key, (dep = new Set()))
}
if (!dep.has(activeEffect)) {
  dep.add(activeEffect)
  activeEffect.deps.push(dep)
}

單純從這段代碼出發(fā)去解讀的話,可能會(huì)有一定的困難,換個(gè)角度,從vue3的整體使用情況出發(fā),返回來解讀這段代碼

setup() {
  const b = reactive({
    c: 1,
    b: 2,
  });
  // effect是vue中的reactivity包直接返回出來的方法
  const a = effect(() => {
    return b.c;
  })
}

首先,在effect中使用了前面通過reactive定義的b,從表面現(xiàn)象出發(fā)的話,我們能知道,當(dāng)b.c發(fā)生變化的時(shí)候,a也會(huì)同步發(fā)生變化

這個(gè)變化的原因就是上述源碼中的activeEffect,當(dāng)創(chuàng)建的effect被調(diào)用的時(shí)候,會(huì)將activeEffect設(shè)置為自身,并執(zhí)行相應(yīng)的回調(diào)函數(shù),函數(shù)的調(diào)用會(huì)觸發(fā)到各自使用到的數(shù)據(jù)的getter,將對(duì)應(yīng)的effect依賴注入到每個(gè)使用的數(shù)據(jù)上

至于為什么會(huì)設(shè)置這么復(fù)雜的一個(gè)屬性的依賴獲取,是因?yàn)槭褂胮roxy的原因,proxy代理了一整個(gè)對(duì)象,就不能像vue2使用Obect.defineProperty直接在getter里面就當(dāng)前的字段進(jìn)行一個(gè)依賴綁定,所以在vue3中是直接將整個(gè)對(duì)象作為一個(gè)Map,每個(gè)Map的key都是對(duì)應(yīng)的屬性,而value則是所有依賴當(dāng)前屬性的對(duì)象

set

同get,依舊保持著原先的思路跟模式

  1. 設(shè)置當(dāng)前數(shù)據(jù)
  2. 發(fā)布已訂閱的數(shù)據(jù)(觸發(fā)依賴更新)

在vue3中,還是有部分區(qū)別的,畢竟是單獨(dú)拉出去的一個(gè)庫

  1. 如果直接調(diào)用effect,當(dāng)檢測(cè)的數(shù)據(jù)發(fā)生變化的時(shí)候會(huì)直接修改
  2. 如果調(diào)用watch或者watchEffect,則會(huì)走vue自身的調(diào)度方案

所以,如果想當(dāng)前的數(shù)據(jù)直接可以更新的話, 可以優(yōu)先使用effect,他會(huì)比watchEffect的更新速度快一點(diǎn),劣勢(shì)是可能很多東西得自己寫 =,=

至于怎么實(shí)現(xiàn)的其實(shí)就很簡(jiǎn)單了

  1. 獲取當(dāng)前更新的數(shù)據(jù)的受依賴項(xiàng)
  2. 分組進(jìn)入等待運(yùn)行的Set中
  3. 執(zhí)行

但是里面有一個(gè)特殊的處理,針對(duì)于數(shù)組的length屬性,這個(gè)屬性是有一定區(qū)別的,接下來具體講講在vue3中的數(shù)組操作

數(shù)組

在vue2中的,針對(duì)數(shù)組是多做了一層處理,代理了數(shù)組的基本方法,這是因?yàn)槭褂肙bject.defineProperty在數(shù)組上面天然存在劣勢(shì)

具體原因在vue的文檔中寫的非常清楚了,這里就不詳細(xì)敘述了

文檔地址

而在vue3中使用proxy就完美的解決了這個(gè)問題,只是因?yàn)閜roxy能夠監(jiān)聽數(shù)組的變化,做個(gè)測(cè)試

const a = new Proxy([1,2], {
  get: function(obj, prop) {
    console.log('get', obj, prop);
    return Reflect.get(obj, prop);
  },
  set: function(obj, prop, value) {
    console.log('set', obj, prop, value);
    return Reflect.set(obj, prop, value);
  },
});
a.push(1);

get [1,2] push
get [1,2] length
set [1,2] 2 1
set [1,2, 1] length 3

當(dāng)我們代理了一個(gè)數(shù)組之后,直接調(diào)用push插入一個(gè)新的數(shù)據(jù),能夠明顯的看到getter跟setter都會(huì)被調(diào)用兩次,一次是調(diào)用的push方法,而另一次是數(shù)組的長(zhǎng)度length,也就是說,proxy不僅僅會(huì)檢測(cè)到我們當(dāng)前調(diào)用的方法,還能夠知道我們的數(shù)據(jù)長(zhǎng)度是否發(fā)生了變化

看到這邊,可能會(huì)有一個(gè)疑惑,push是對(duì)當(dāng)前數(shù)組進(jìn)行的操作,但是數(shù)組里面還有部分方法是會(huì)返回一個(gè)新的數(shù)組,proxy是否會(huì)對(duì)新生成的數(shù)組也進(jìn)行代理,這里我們拿splice舉個(gè)例子

// a= [1,2]
a.splice(0, 1)

get [1,2] push
get [1,2] length
get [1,2] constructor
get [1,2] 0
get [1,2] 1
set [1,2] 0 2
set [2,empty] length 1

從表現(xiàn)形式來看,proxy代理之后的數(shù)組只會(huì)對(duì)當(dāng)前數(shù)組的內(nèi)容進(jìn)行監(jiān)聽,也就是調(diào)用splice之后新生成的數(shù)組的變化是不會(huì)被代理的

現(xiàn)在我們回過頭來看下vue3的trigger方法,這個(gè)是vue在set完成之后觸發(fā)的依賴更新,同樣的掐個(gè)頭去個(gè)尾,除去正常的執(zhí)行以外,我們看下針對(duì)數(shù)組做的優(yōu)化

// add方法是將當(dāng)前的依賴項(xiàng)添加進(jìn)一個(gè)等待更新的數(shù)組中
else if (key === 'length' && isArray(target)) {
  depsMap.forEach((dep, key) => {
   if (key === 'length' || key >= (newValue as number)) {
    add(dep)
   }
  })
} 

由于我們知道, 在一次操作數(shù)組的時(shí)候會(huì)進(jìn)行多次的set,那么如果每次set都要去更新依賴的話,會(huì)造成性能上的浪費(fèi),所以在vue3里面只有在set length的時(shí)候才會(huì)去調(diào)用add方法,然后統(tǒng)一執(zhí)行所有的更新

結(jié)語

不得不說,proxy比defineProperty強(qiáng)大了太多,不僅解決了vue的歷史難題,讓vue的體驗(yàn)更上了一層,更是去除了不少因?yàn)閐efineProperty而必須要的方法,精簡(jiǎn)了vue的包大小

雖然proxy的兼容性是比defineProperty差不少,但是在vue里面基本已經(jīng)拋棄了IE,所以如果你的項(xiàng)目需要在ie下運(yùn)行的話,那就請(qǐng)放棄vue這個(gè)選擇,使用低版本的react的吧,哈哈哈哈哈哈

在移動(dòng)端里面基本上就是沒有這種版本的限制,實(shí)在是版本低不能使用proxy的話,相信去找找polyfill是能夠找到的

到此這篇關(guān)于vue3為什么要用proxy替代defineProperty的文章就介紹到這了,更多相關(guān)vue3 proxy替代defineProperty內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用vue-resource進(jìn)行數(shù)據(jù)交互的實(shí)例

    使用vue-resource進(jìn)行數(shù)據(jù)交互的實(shí)例

    下面小編就為大家?guī)硪黄褂胿ue-resource進(jìn)行數(shù)據(jù)交互的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • Vue路由權(quán)限控制解析

    Vue路由權(quán)限控制解析

    這篇文章主要介紹了Vue路由權(quán)限控制的相關(guān)資料,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下
    2020-11-11
  • vue項(xiàng)目使用axios封裝request請(qǐng)求的過程

    vue項(xiàng)目使用axios封裝request請(qǐng)求的過程

    這篇文章主要介紹了vue項(xiàng)目使用axios封裝request請(qǐng)求,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • el-descriptions引入代碼中l(wèi)abel不生效問題及解決

    el-descriptions引入代碼中l(wèi)abel不生效問題及解決

    這篇文章主要介紹了el-descriptions引入代碼中l(wèi)abel不生效問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • vue通過過濾器實(shí)現(xiàn)數(shù)據(jù)格式化

    vue通過過濾器實(shí)現(xiàn)數(shù)據(jù)格式化

    這篇文章主要介紹了vue通過過濾器實(shí)現(xiàn)數(shù)據(jù)格式化的方法,文中講解非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • VUE2.0+ElementUI2.0表格el-table循環(huán)動(dòng)態(tài)列渲染的寫法詳解

    VUE2.0+ElementUI2.0表格el-table循環(huán)動(dòng)態(tài)列渲染的寫法詳解

    這篇文章主要介紹了VUE2.0+ElementUI2.0表格el-table循環(huán)動(dòng)態(tài)列渲染的寫法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Vue MVVM模型超詳細(xì)講解

    Vue MVVM模型超詳細(xì)講解

    MVVM是Model-View-ViewModel的縮寫,MVVM是一種設(shè)計(jì)思想,這篇文章主要介紹了Vue生命周期和MVVM框架,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-11-11
  • Vue3啟用gzip壓縮nginx配置詳解

    Vue3啟用gzip壓縮nginx配置詳解

    這篇文章主要為大家介紹了Vue3啟用gzip壓縮時(shí)nginx配置gzip示例詳解詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • vue實(shí)現(xiàn)在進(jìn)行增刪改操作后刷新頁面

    vue實(shí)現(xiàn)在進(jìn)行增刪改操作后刷新頁面

    這篇文章主要介紹了vue實(shí)現(xiàn)在進(jìn)行增刪改操作后刷新頁面,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Vue3非遞歸渲染Tree組件的初步實(shí)現(xiàn)代碼

    Vue3非遞歸渲染Tree組件的初步實(shí)現(xiàn)代碼

    這篇文章主要介紹了Vue3非遞歸渲染Tree組件的初步實(shí)現(xiàn),文中通過代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定幫助,需要的朋友可以參考下
    2024-05-05

最新評(píng)論