картина
изображение.png

предисловие

vue3Он был в центре внимания в течение двух лет с момента его выпуска, и теперь у него есть импульс, чтобы поделиться миром с реагировать, Мы знаем, что это основано на способности прокси-сервера достигать отзывчивости, что решило некоторые vue2из оставшихся проблем. в то же время, благодаря характеристикам прокси, он также улучшил производительность во время выполнения

У всего есть преимущества и недостатки proxy, хотя он и непобедим, но также имеет свои ограничения, что приводит к некоторым недостаткам, на мой взгляд (на самом деле, он не соответствует естественному способу написания языка js, некоторые люди думают, что это особый метод написания, и он не относится к недостаткам)

  • 1. Реализация отзывчивой системы примитивных значений приводит к тому, что она должна быть упакована как объект и доступ .valueк ней посредством
  • 2. Деструктурирование ES6 нельзя использовать по желанию. сломал бы его отзывчивую натуру

Движимый любопытством, я исследовал и обдумал, почему он вызвал эти два недостатка.

Реализация реактивной системы для примитивных значений

Прежде чем понять реализацию реактивной системы примитивных значений, давайте сначала рассмотрим возможности прокси!

const obj = {
  name'win'
}

const handler = {
  getfunction(target, key){
    console.log('get--', key)
    return Reflect.get(...arguments)  
  },
  setfunction(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')

复制代码

В приведенном выше коде мы обнаружили, что использование прокси само по себе является перехватом объекта new Proxy, а объект obj перехватывается через возвращаемое значение

Таким образом, когда вы получаете доступ к значению в объекте, он запускает getметод , а когда вы изменяете значение в объекте, он запускает setметод .

Но когда дело доходит до исходного значения, у него нет объекта, что делать, его new proxyнельзя использовать.

В отчаянии мы можем только завернуть его, поэтому у нас есть .valueдоступ к использованию

Давайте посмотрим на конкретную реализацию

import { reactive } from "./reactive";
import { trackEffects, triggerEffects } from './effect'

export const isObject = (value) => {
    return typeof value === 'object' && value !== null
}

// 将对象转化为响应式的
function toReactive(value{
    return isObject(value) ? reactive(value) : value
}

class RefImpl {
    public _value;
    public dep = new Set// 依赖收集
    public __v_isRef = true// 是ref的标识
    // rawValue 传递进来的值
    constructor(public rawValue, public _shallow) {
        // 1、判断如果是对象 使用reactive将对象转为响应式的
        // 浅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);
            // 赋值完 将初始值变为本次的
            this.rawValue = newVal
            triggerEffects(this.dep)
        }
    }
}

复制代码

Приведенный выше код представляет собой упаковку исходного значения, оно упаковано как объект, и доступ к исходному значению осуществляется через методы get valueи , в результате чего выполняется необходимая операция, что на самом деле является беспомощным выбором.set value.value

相当于两瓶毒药,你得选一瓶Нельзя есть и рыбу, и медвежью лапу

Почему деструктурирование ES6 и невозможность его использования разрушит его адаптивные функции

Первый вопрос, наконец, понят, поэтому давайте рассмотрим второй самый важный вопрос,为什么结构赋值,会破坏响应式特性

фон прокси

Прежде чем мы начнем, давайте обсудим, почему изменение响应式方案

Vue2 основан на Object.defineProperty   , но имеет много дефектов, таких как  невозможность отслеживать модификацию массива на основе индексов, а также не поддерживаются такие дефекты, как Map, Set, WeakMap и WeakSet  .

На самом деле, это не задерживает наше развитие, vue2 по-прежнему остается мейнстримом,

Насколько я понимаю 与时俱进, 新一代的版本,一定要紧跟语言的特性,一定要符合新时代的书写风格хотя proxyи есть много улучшений по сравнению с Object.defineProperty, он не лишен недостатков.Например,不兼容IE

Как может быть что-то совершенное в мире?

Ваше великое мужество заключается в том, чтобы отказаться от настоящего, чтобы построить будущее!

Принцип реализации

Разобравшись с предысторией, давайте рассмотрим принцип в режиме фейка proxy, хотя это все тухло.

Однако при написании гидрологии на что следует обратить внимание: два слова - когерентность

картина
изображение.png
        const obj = {
            count1
        };
        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 можно реализовать перехват объектов.

картина
изображение.png

С такой зависимостью можно добиться отзывчивости, можно обнаружить, что весь объект этого obj перехватывается, но вы обнаружите, что объект вложен на один уровень глубже.

Например:


    const obj = {
            count1,
            b: {
                c2
            }
        };
        
        
     console.log(proxy.b)
     console.log(proxy.b.c)
复制代码

Он не может перехватить, мы должны упаковать

    const obj = {
            a: {
                count1
            }
        };
        
        function reactive(obj{
            return new Proxy(obj, {
                get(target, key, receiver) {
                    console.log("这里是get");
                    // 判断如果是个对象在包装一次,实现深层嵌套的响应式
                    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);
复制代码

Ну, принцип сделан, давайте формально изучим

Теперь перечислю несколько известных мне ситуаций, в которых теряется отзывчивость:

  • 1. Деконструировать  props объект, потому что он теряет свою отзывчивость
  • 2. Прямое присвоение reactiveреактивных объектов
  • 3. vuexНазначение API средней комбинации

Разрушение  props объектов, потому что они теряют отзывчивость

       const obj = {
            a: {
                count1
            },
            b1
        };
            
            //reactive 是上文中的reactive
           const proxy = reactive(obj);
        const {
            a,
            b
        } = proxy;
        console.log(a)
        console.log(b)
        console.log(a.count)
        
复制代码
картина
изображение.png

В приведенном выше коде мы обнаруживаем, что присваивание деструктурирования, b 不会触发响应式, a如果你访问的时候, вызовет отклик

Почему это?

Не волнуйтесь, давайте объясним по одному?

Давайте сначала обсудим, почему деструктурирующее задание потеряет отзывчивость?

Мы знаем деструктурирующее присваивание, различаем присваивание примитивных типов и присваивание ссылочных типов,

原始类型的赋值相当于按值传递,引用类型的值就相当于按引用传递

эквивалентно

   // 假设a是个响应式对象
  const a={ b:1}
  // c 此时就是一个值跟当前的a 已经不沾边了
  const c=a.b

// 你直接访问c就相当于直接访问这个值 也就绕过了 a 对象的get ,也就像原文中说的失去响应式
复制代码

Так почему aже он отзывчив?

Поскольку aэто ссылочный тип, мы помним решение в приведенном выше коде. Если он, objectто переупаковать как реактивный

Формально из-за текущей фичи, если это ссылочный тип, вы не потеряете отзывчивость при доступе к его содержимому

  // 假设a是个响应式对象
 const a={ b:{c:3}}
 // 当你访问a.b的时候就已经重新初始化响应式了,此时的c就已经是个代理的对象
 const c=a.b

// 你直接访问c就相当于访问一个响应式对象,所以并不会失去响应式
复制代码

Вышеприведенное примерно объясняет, почему присваивание деструктурирования может потерять отзывчивость.Я думаю, документу лень объяснять причину, поэтому я просто установил правило, вы!

Не используйте его, сохраните ошибки, которые вы считаете vueправдой, и заранее измените привычки пользователя! Не используется для

Прямое присвоение reactiveреактивных объектов

Когда мы впервые использовали vue3, мы указали, что будет написан следующий код

 const vue = reactive({ a1 })
 vue = { b2 }

复制代码

А потом задавать вопросы reactiveразве это не отзывчиво? Почему после того, как я присвоил значение, у него пропала отзывчивость, а потом он орал, фигня вью

На самом деле, это потому, что вы не понимаете концепцию js native, на самом деле 尤大вы приложили максимум усилий, чтобы не допустить ошибок.

Например, из-за проблемы деструктурирующего присваивания он прямо запрещает реактивное деструктурирующее присваивание.

картина
изображение.png

Когда вы используете операцию присваивания деструктурирования, она напрямую отключает

Потом кто-то снова спросил, 为啥props 不给禁用了呢?

因为你的props 的数据可能不是响应式的啊,不是响应式的,我得能啊, особенно он не может мешать пользователю использовать новый синтаксис.

Так что это одно и то же предложение: 框架现在的呈现,其实充满了取舍Иногда это действительно две бутылки яда, выбери одну!

Вернемся к теме, поговорим о нативном синтаксисе js.

Первое, что нужно подтвердить, это то, что назначение ссылочного типа нативного js на самом деле основано на ссылочном адресе!

 // 当reactive 之后返回一个代理对象的地址被vue 存起来,
 // 用一个不恰当的比喻来说,就是这个地址具备响应式的能力
 const vue = reactive({ a1 })
 
 //  而当你对于vue重新赋值的时候不是将新的对象赋值给那个地址,而是将vue 换了个新地址
 // 而此时新地址不具备响应式,可不就失去响应式了吗
 vue = { b2 }

复制代码

Выше приведено reactiveобъяснение потери отзывчивости, так что это также причина, по которой многие пользователи ругаются.不符合他的使用习惯了,这都是被vue2 培养起来的一代

Здесь я хочу сказать честное слово за Тебя Да 人家又没收你钱,还因为他,你有口饭吃,

Ты сам не можешь идти в ногу со временем и принимать новое, это ты 能耐,

это типично端起碗吃肉,放下筷子骂娘

vuexНазначение API средней композиции

Использование присваивания в vuex также может привести к потере отклика.


import { computed } from 'vue'
import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()
    return {
      // 在 computed 函数中访问 state
      count: computed(() => store.state.count),

      // 在 computed 函数中访问 getter
      double: computed(() => store.getters.double)
    }
  }
}

复制代码

В приведенном выше коде мы обнаружили, что store.getters.doubleнеобходимо computedобернуть с помощью . На самом деле причина та же, и она же является причиной присваивания переменных, здесь мы их повторять не будем!

в конце концов

Эта статья, в процессе использования vue3, некоторый опыт и исследования после майнинга, надеюсь, она будет вам полезна, чтобы вы могли получить повышение и прибавку к зарплате на работе!

Наконец, в конце концов, я буду продвигать свой анализ исходного кода vue.Может быть, анализ не очень хороший, но он весь читается построчно.Может быть, вы можете подумать о предложении или предложении после его прочтения, что полезно!

Адрес анализа исходного кода [1]

приветственная звезда

Об этой статье

Автор: фермер Лао Цзи

https://juejin.cn/post/7114596904926740493

Конец

Если вы найдете этот контент вдохновляющим, я хотел бы попросить вас сделать мне три небольших одолжения:
1. Нажмите  «Просматриваю» , чтобы этот контент увидело больше людей.
2. Следите за официальным сайтом  https://muyiy.cn , давайте установим долгосрочные отношения.
3. Обратите внимание на официальную учетную запись «Advanced Front-end Advanced» и ответьте  на «Добавить группу» на фоне официальной учетной записи.  Присоединяйтесь к нам, чтобы узнать и отправить вам хорошо организованные вопросы для расширенного внешнего интерфейса.

》》Банк вопросов, который используют интервьюеры, приходите и смотрите 《


Не забудьте поставить лайк в конце!картина

Удачи в 2022 году! Жестокая красота! Сильно худой!