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

vue3解構(gòu)賦值失去響應(yīng)式引發(fā)的問題思考

 更新時間:2022年06月30日 11:51:07   作者:??老驥farmer????  
這篇文章主要介紹了vue3解構(gòu)賦值失去響應(yīng)式引發(fā)的問題思考,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下

前言

vue3發(fā)布以來經(jīng)歷兩年風(fēng)頭正盛,現(xiàn)在大有和react 平分天下的勢頭,我們知道他是基于proxy 實現(xiàn)響應(yīng)式的能力, 解決了vue2所遺留下來的一些問題,同時也正由于proxy的特性,也提高了運行時的性能

凡事有利有弊, proxy雖然無敵,但是他也有本身的局限,從而產(chǎn)生一些我認(rèn)為的弊端(其實就是不符合js語言的自然書寫方式,有的人覺得就是個特殊寫法,他不屬于弊端)

  • 1、 原始值的響應(yīng)式系統(tǒng)的實現(xiàn) 導(dǎo)致必須將他包裝為一個對象, 通過 .value 的方式訪問
  • 2、 ES6 解構(gòu),不能隨意使用。會破壞他的響應(yīng)式特性

好奇心驅(qū)使,研究琢磨了一下,為什么他會造成這兩個弊端

原始值的響應(yīng)式系統(tǒng)的實現(xiàn)

在理解原始值的響應(yīng)式系統(tǒng)的實現(xiàn),我們先來溫習(xí)一下proxy 的能力!

const obj = {
  name: 'win'
}
const handler = {
  get: function(target, key){
    console.log('get--', key)
    return Reflect.get(...arguments)  
  },
  set: function(target, key, value){
    console.log('set--', key, '=', value)
    return Reflect.set(...arguments)
  }
}
const data = new Proxy(obj, handler)
data.name = 'ten'
console.log(data.name,'data.name22')

上述代碼中,我們發(fā)現(xiàn),proxy 的使用本身就是對于 對象的攔截, 通過new Proxy 的返回值,攔截了obj 對象如此一來,當(dāng)你 訪問對象中的值的時候,他會觸發(fā) get 方法, 當(dāng)你修改對象中的值的時候 他會觸發(fā) set方法但是到了原始值的時候,他沒有對象啊,咋辦呢,new proxy 排不上用場了。無奈之下,我們只能包裝一下了,所以就有了使用.value訪問了

我們來看看具體實現(xiàn):

import { reactive } from "./reactive";
import { trackEffects, triggerEffects } from './effect'
export const isObject = (value) => {
    return typeof value === 'object' && value !== null
}
// 將對象轉(zhuǎn)化為響應(yīng)式的
function toReactive(value) {
    return isObject(value) ? reactive(value) : value
}
class RefImpl {
    public _value;
    public dep = new Set; // 依賴收集
    public __v_isRef = true; // 是ref的標(biāo)識
    // rawValue 傳遞進來的值
    constructor(public rawValue, public _shallow) {
        // 1、判斷如果是對象 使用reactive將對象轉(zhuǎn)為響應(yīng)式的
        // 淺ref不需要再次代理
        this._value = _shallow ? rawValue : toReactive(rawValue);
    }
    get value() {
        // 取值的時候依賴收集
        trackEffects(this.dep)
        return this._value;
    }
    set value(newVal) {
        if (newVal !== this.rawValue) {
            // 2、set的值不等于初始值 判斷新值是否是對象 進行賦值
            this._value = this._shallow ? newVal : toReactive(newVal);
            // 賦值完 將初始值變?yōu)楸敬蔚?
            this.rawValue = newVal
            triggerEffects(this.dep)
        }
    }
}

上述代碼,就是對于原始值,的包裝,他被包裝為一個對象,通過get value 和set value 方法來進行原始值的訪問,從而導(dǎo)致必須有.value 的操作 ,這其實也是個無奈的選擇

相當(dāng)于兩瓶毒藥,你得選一瓶 魚與熊掌不可兼得

為什么ES6 解構(gòu),不能隨意使用會破壞他的響應(yīng)式特性

第一個問題終于整明白了,那么我們來看看最重要的第二個問題,為什么結(jié)構(gòu)賦值,會破壞響應(yīng)式特性

proxy背景

在開始之前,我們先來討論一下為什么要更改響應(yīng)式方案

vue2 基于Object.defineProperty  ,但是他有很多缺陷,比如 無法監(jiān)聽數(shù)組基于下標(biāo)的修改,不支持 Map、Set、WeakMap 和 WeakSet等缺陷 ,

其實這些也也不耽誤我們開發(fā), vue2到現(xiàn)在還是主流,

我的理解就是與時俱進, 新一代的版本,一定要緊跟語言的特性,一定要符合新時代的書寫風(fēng)格,雖然proxy相對于Object.defineProperty 有很多進步, 但是也不是一點缺點都沒有,你比如說 不兼容IE

天底下的事情,哪有完美的呢?尤大的魄力就在于,舍棄一點現(xiàn)在,博一個未來!

實現(xiàn)原理

在理解了背景之后,我們再來假模假式的溫習(xí)一下proxy 原理,雖然這個都被講爛了。

但是,寫水文,講究什么:倆字-連貫

        const obj = {
            count: 1
        };
        const proxy = new Proxy(obj, {
            get(target, key, receiver) {
                console.log("這里是get");
                return Reflect.get(target, key, receiver);
            },
            set(target, key, value, receiver) {
                console.log("這里是set");
                return Reflect.set(target, key, value, receiver);
            }
        });
        
        console.log(proxy)
        console.log(proxy.count)

以上代碼就是Proxy的具體使用方式,通過和Reflect 的配合, 就能實現(xiàn)對于對象的攔截

如此依賴,就能實現(xiàn)響應(yīng)式了,大家可以發(fā)現(xiàn),這個obj的整個對象就被攔截了,但是你發(fā)現(xiàn)對象在嵌套深一層

比如:

    const obj = {
            count: 1,
            b: {
                c: 2
            }
        };
     console.log(proxy.b)
     console.log(proxy.b.c)

他就無法攔截了,我們必須要來個包裝

    const obj = {
            a: {
                count: 1
            }
        };
        function reactive(obj) {
            return new Proxy(obj, {
                get(target, key, receiver) {
                    console.log("這里是get");
                    // 判斷如果是個對象在包裝一次,實現(xiàn)深層嵌套的響應(yīng)式
                    if (typeof target[key] === "object") {
                        return reactive(target[key]);
                    };
                    return Reflect.get(target, key, receiver);
                },
                set(target, key, value, receiver) {
                    console.log("這里是set");
                    return Reflect.set(target, key, value, receiver);
                }
            });
        };
        const proxy = reactive(obj);

好了,原理搞完了,我們來正式研究一下現(xiàn)在列舉一下我知道的響應(yīng)式失去的幾個情況:

  • 1、解構(gòu) props 對象,因為它會失去響應(yīng)式
  • 2、 直接賦值reactive響應(yīng)式對象
  • 3、 vuex中組合API賦值

解構(gòu) props 對象,因為它會失去響應(yīng)式

       const obj = {
            a: {
                count: 1
            },
            b: 1
        };
            //reactive 是上文中的reactive
           const proxy = reactive(obj);
        const {
            a,
            b
        } = proxy;
        console.log(a)
        console.log(b)
        console.log(a.count)

上述代碼中,我們發(fā)現(xiàn), 解構(gòu)賦值,b 不會觸發(fā)響應(yīng)式,a如果你訪問的時候,會觸發(fā)響應(yīng)式

這是為什么呢?別急我們一個個解釋?先來討論為什么解構(gòu)賦值,會丟失響應(yīng)式呢?我們知道解構(gòu)賦值,區(qū)分原始類型的賦值,和引用類型的賦值,

原始類型的賦值相當(dāng)于按值傳遞, 引用類型的值就相當(dāng)于按引用傳遞

就相當(dāng)于:

   // 假設(shè)a是個響應(yīng)式對象
  const a={ b:1}
  // c 此時就是一個值跟當(dāng)前的a 已經(jīng)不沾邊了
  const c=a.b
// 你直接訪問c就相當(dāng)于直接訪問這個值 也就繞過了 a 對象的get ,也就像原文中說的失去響應(yīng)式

那為啥a 具備響應(yīng)式呢?

因為a 是引用類型,我們還記得上述代碼中的一個判斷嗎。如果他是個object 那么就重新包裝為響應(yīng)式

正式由于當(dāng)前特性,導(dǎo)致,如果是引用類型, 你再去訪問其中的內(nèi)容的時候并不會失去響應(yīng)式

  // 假設(shè)a是個響應(yīng)式對象
 const a={ b:{c:3}}
 // 當(dāng)你訪問a.b的時候就已經(jīng)重新初始化響應(yīng)式了,此時的c就已經(jīng)是個代理的對象
 const c=a.b
// 你直接訪問c就相當(dāng)于訪問一個響應(yīng)式對象,所以并不會失去響應(yīng)式

以上就大致解釋了為什么解構(gòu)賦值,可能會失去響應(yīng)式,我猜的文檔中懶得解釋其中緣由,索性就定了個規(guī)矩,您??!

就別用了,省的以為是vue的bug,提前改變用戶的使用習(xí)慣!不慣著

直接賦值reactive響應(yīng)式對象

我們最初使用vue3的時候,指定會寫出以下代碼

 const vue = reactive({ a: 1 })
 vue = { b: 2 }

然后就發(fā)出疑問reactive不是響應(yīng)式的嗎? 為啥我賦值了以后,他的響應(yīng)式就沒了 ,接著破口大罵,垃圾vue

其實啊,這就是您對于js 原生的概念不清除,其實尤大 已經(jīng)做了最大的努力,來防止你進行錯誤操作了

比如,由于解構(gòu)賦值的問題, 他直接禁止了reactive的解構(gòu)賦值

當(dāng)你用解構(gòu)賦值操作的時候,他直接禁用了那有人又問了, 為啥props 不給禁用了呢?因為你的props 的數(shù)據(jù)可能不是響應(yīng)式的啊,不是響應(yīng)式的,我得能啊,尤大他也不能干涉用戶使用新語法啊

所以還是那句話:框架現(xiàn)在的呈現(xiàn),其實充滿了取舍,有時候真是兩瓶毒藥,挑一瓶!

回歸正題,我們再來說說 原生js 語法,首先需要確認(rèn)的是,原生js 的引用類型的賦值,其實是 按照引用地址賦值!

 // 當(dāng)reactive 之后返回一個代理對象的地址被vue 存起來,
 // 用一個不恰當(dāng)?shù)谋扔鱽碚f,就是這個地址具備響應(yīng)式的能力
 const vue = reactive({ a: 1 })
 //  而當(dāng)你對于vue重新賦值的時候不是將新的對象賦值給那個地址,而是將vue 換了個新地址
 // 而此時新地址不具備響應(yīng)式,可不就失去響應(yīng)式了嗎
 vue = { b: 2 }

以上就是reactive失去響應(yīng)式的解釋,所以這個也是很多用戶罵罵咧咧的原因。不符合他的使用習(xí)慣了,這都是被vue2 培養(yǎng)起來的一代

在這里我要替,尤大說句公道話,人家又沒收你錢,還因為他,你有口飯吃,您自己不能與時俱進,擁抱新事物,那是您沒能耐,這是典型的端起碗吃肉,放下筷子罵娘

vuex中組合API賦值

在vuex 用賦值也可能會失去響應(yīng)式:

import { computed } from 'vue'
import { useStore } from 'vuex'
export default {
  setup () {
    const store = useStore()
    return {
      // 在 computed 函數(shù)中訪問 state
      count: computed(() => store.state.count),

      // 在 computed 函數(shù)中訪問 getter
      double: computed(() => store.getters.double)
    }
  }
}

以上代碼中我們發(fā)現(xiàn)store.getters.double 必須用computed 包裹起來,其實道理是一樣的,也是變量賦值的原因,在這里我們就不再贅述!

結(jié)語

到此這篇關(guān)于vue3結(jié)構(gòu)賦值失去響應(yīng)式引發(fā)的問題思考的文章就介紹到這了,更多相關(guān)vue3結(jié)構(gòu)賦值內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 老生常談vue的生命周期

    老生常談vue的生命周期

    這篇文章主要為大家詳細(xì)介紹了vue的生命周期,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Vue.js實戰(zhàn)之通過監(jiān)聽滾動事件實現(xiàn)動態(tài)錨點

    Vue.js實戰(zhàn)之通過監(jiān)聽滾動事件實現(xiàn)動態(tài)錨點

    監(jiān)聽事件是我們在使用vue.js的時候經(jīng)常使用的一個功能,下面這篇文章主要介紹了Vue.js實戰(zhàn)之通過監(jiān)聽滾動事件實現(xiàn)動態(tài)錨點 的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),相信對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-04-04
  • 詳解Vue串聯(lián)過濾器的使用場景

    詳解Vue串聯(lián)過濾器的使用場景

    這篇文章主要介紹了詳解Vue串聯(lián)過濾器的使用場景,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • vue mint-ui tabbar變組件使用

    vue mint-ui tabbar變組件使用

    這篇文章主要介紹了vue mint-ui tabbar變組件使用方法及實例代碼,非常不錯具有參考借鑒價值,需要的朋友可以參考下
    2018-05-05
  • Vuex之理解Mutations的用法實例

    Vuex之理解Mutations的用法實例

    本篇文章主要介紹了Vuex之理解Mutations的用法實例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • vue自動添加瀏覽器兼容前后綴操作

    vue自動添加瀏覽器兼容前后綴操作

    這篇文章主要介紹了vue自動添加瀏覽器兼容前后綴操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • 簡單實現(xiàn)vue中的依賴收集與響應(yīng)的方法

    簡單實現(xiàn)vue中的依賴收集與響應(yīng)的方法

    這篇文章主要介紹了簡單實現(xiàn)vue中的依賴收集與響應(yīng)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • vue項目完成后如何實現(xiàn)項目優(yōu)化的示例

    vue項目完成后如何實現(xiàn)項目優(yōu)化的示例

    本文主要介紹了vue項目完成后如何實現(xiàn)項目優(yōu)化的示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 詳解vue-cli項目中的proxyTable跨域問題小結(jié)

    詳解vue-cli項目中的proxyTable跨域問題小結(jié)

    這篇文章主要介紹了詳解vue-cli項目中的proxyTable跨域問題小結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • vue圖片加載與顯示默認(rèn)圖片實例代碼

    vue圖片加載與顯示默認(rèn)圖片實例代碼

    這篇文章主要為大家詳細(xì)介紹了vue圖片加載與顯示默認(rèn)圖片的實例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03

最新評論