Узнайте о прокси Vue2 и Vue3 в одной статье

Vue.js

скажи привет

Всем привет, я Дерек, и я снова с вами встречаюсь.

Когда я на шестой день пожаловался, почему праздник такой короткий, был уже седьмой день.

Желаю всем счастливого седьмого дня и хорошего начала работы! ! !

коммерческое время:

Текст начинается здесь.

Прокси-реализация Vue2

Как мы все знаем, способ реализации прокси в Vue2 — это перехват данных, то есть использованиеObject.defineProperty; Простой пример выглядит следующим образом:

var obj = {};
var initValue = 20;

Object.defineProperty(obj, "age", {
  get: function () {
    console.log('get')
    return initValue;
  },
  set: function (value) {
    console.log('set')
    initValue = value;
  }
});

console.log(obj.age);
obj.age = 22;
console.log(obj.age);

Как и выше, консоль выведет:

В Vue2 перехват данных фактически реализован таким образом, при котором get будет собирать зависимости:depend, набор вызовет зависимости --notify;прямой исходный код vue-defineReactive

Конечно, есть и обработка массивов, потому что массивы — это относительно особый тип данных, методы массивов в Vue2 были переупакованы, и методы изменения исходных данных массива были переупакованы следующим образом:push、pop、shift、unshift、splice、sort、reverse;Массив vue переупаковывает исходный код напрямую

Что касается того, как реализовано наблюдение в Vue2, я не буду здесь слишком много объяснять, вы можете прочитать эту статью.Интерпретация исходного кода Vue2 — наблюдение

Проблемы с прокси Vue2

В Vue2, даже если массив будет переупакован, все равно будут проблемы, а именно:

var list = ['tom', 'jack', 'draven', 'ifil']
// 直接改变数组的长度,Vue2是监听不到的,
list.length = 3;
// 直接改变数组中的某个元素,Vue2中也是监听不到的,
list[2] = 'luckyDraven';

Хотя Vue2 предоставляет метод Vue.$set для компенсации модификации массива в приведенном выше коде, он также создает дополнительную нагрузку для разработчиков. Официальная документация Vue2 об этой части также объясняет это.О массивах

Прокси для Vue3

Vue3 отказался от перехвата данных в пользуProxy+Reflectдля реализации брокера данных.

что такое прокси

Объект Proxy используется для создания прокси для объекта, позволяющего перехватывать и настраивать основные операции (такие как поиск свойств, назначение, перечисление, вызов функций и т. д.). Синтаксис конструктора Proxy:

const p = new Proxy(target, handler)
  • target: целевой объект для переноса с помощью прокси (может быть объект любого типа, включая собственные массивы, функции или даже другой прокси).
  • обработчик: объект, который обычно имеет функции в качестве атрибутов, и функции в каждом атрибуте определяют поведение прокси p при выполнении различных операций.

Методы, которые могут содержать обработчики (также называемые ловушками), следующие:

// Object.getPrototypeOf 方法的捕捉器。
handler.getPrototypeOf()

// Object.setPrototypeOf 方法的捕捉器。
handler.setPrototypeOf()

// Object.isExtensible 方法的捕捉器。
handler.isExtensible()

// Object.preventExtensions 方法的捕捉器。
handler.preventExtensions()

// Object.getOwnPropertyDescriptor 方法的捕捉器。
handler.getOwnPropertyDescriptor()

// Object.defineProperty 方法的捕捉器。
handler.defineProperty()

// in 操作符的捕捉器。
handler.has()

// 属性读取操作的捕捉器。
handler.get()

// 属性设置操作的捕捉器。
handler.set()

// delete 操作符的捕捉器。
handler.deleteProperty()

// Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。
handler.ownKeys()

// 函数调用操作的捕捉器。
handler.apply()

// new 操作符的捕捉器。
handler.construct()

Вот официальный пример:

const handler = {
    get: function(obj, prop) {
        return prop in obj ? obj[prop] : 37;
    }
};

const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;

console.log(p.a, p.b);      // 1, undefined
console.log('c' in p, p.c); // false, 37

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

Что такое отражение

Reflect — это встроенный объект, предоставляющий методы для перехвата операций JavaScript. Эти методы такие же, как у обработчиков прокси. Reflect не является функциональным объектом, поэтому его нельзя построить.

В отличие от большинства глобальных объектов Reflect не является конструктором, поэтому его нельзя вызвать с помощью оператора new или объекта Reflect как функции. Все свойства и методы Reflect статичны (точно так же, как объекты Math).

Объекты Reflect предоставляют следующие статические методы, связанные сproxy handler methodsназываются одинаково.

грамматика:


// 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。
// 和 Function.prototype.apply() 功能类似。
Reflect.apply(target, thisArgument, argumentsList)

// 对构造函数进行 new 操作,相当于执行 new target(...args)。
Reflect.construct(target, argumentsList[, newTarget])

// 和 Object.defineProperty() 类似。如果设置成功就会返回 true
Reflect.defineProperty(target, propertyKey, attributes)

// 作为函数的delete操作符,相当于执行 delete target[name]。
Reflect.deleteProperty(target, propertyKey)

// 获取对象身上某个属性的值,类似于 target[name]。
Reflect.get(target, propertyKey[, receiver])

// 类似于 Object.getOwnPropertyDescriptor()。
// 如果对象中存在该属性,则返回对应的属性描述符,  否则返回 undefined.
Reflect.getOwnPropertyDescriptor(target, propertyKey)

// 类似于 Object.getPrototypeOf()。
Reflect.getPrototypeOf(target)

// 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
Reflect.has(target, propertyKey)

// 类似于 Object.isExtensible().
Reflect.isExtensible(target)

// 返回一个包含所有自身属性(不包含继承属性)的数组。
// (类似于 Object.keys(), 但不会受enumerable影响).
Reflect.ownKeys(target)

// 类似于 Object.preventExtensions()。返回一个Boolean。
Reflect.preventExtensions(target)

// 将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。
Reflect.set(target, propertyKey, value[, receiver])

// 设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回true。
Reflect.setPrototypeOf(target, prototype)

Например:

  • Проверить, есть ли у объекта определенное свойство

    const duck = {
      name: 'Maurice',
      color: 'white',
      greeting: function() {
        console.log(`Quaaaack! My name is ${this.name}`);
      }
    }
    
    Reflect.has(duck, 'color');
    // true
    Reflect.has(duck, 'haircut');
    // false
    
  • Присвоить значение объекту и получить все свойства объекта

    const duck = {
      name: 'Maurice',
      color: 'white',
      greeting: function() {
        console.log(`Quaaaack! My name is ${this.name}`);
      }
    }
    Reflect.set(duck, 'eyes', 'black'); // returns "true" if successful
    
    console.log(Reflect.ownKeys(duck)); // ["name", "color", "greeting", "eyes"]
    

Часть реализации

Прочитав это, вы должны увидеть, что существует однозначное соответствие между обработчиком в Proxy и статическими методами, поддерживаемыми в Reflect.

В Vue3 прокси-сервер данных реализуется через прокси-сервер в сочетании с Reflect для полного прокси-сервера. Для части анализа исходного кода вы можете проверить эту статьюИнтерпретация исходного кода Vue3 — createReactiveObject.

В Vue3 прокси данных реализуется путем вызова разных обработчиков через разные API. Вставьте картинку в интерпретацию исходного кода:

Сравнение прокси между Vue2 и Vue3

  • через Vue2Object.definePropertyМониторинг массивов не поддерживается, поддерживается только мониторинг объектов;
  • Давайте посмотрим на пример использования Proxy+Reflect в Vue3.
    var list = ["tom", "jack"];
    
    var proxy = new Proxy(list, {
      set: function (target, key, value) {
        Reflect.set(target, key, value);
      }
    });
    
    proxy.length = 3;
    
    console.log(list);  // ["tom", "jack", undefined]
    
    proxy[2] = "draven";
    
    console.log(list); // ["tom", "jack", "draven"]
    

Видно, что длину и прямое назначение в Vue2 нельзя отслеживать с помощью Proxy+Reflect.

the last

Конечно, преимущества Proxy — это не только часть вышеперечисленного массива, но и некоторые другие преимущества, вы можете перейти на официальный сайт для более подробного ознакомления.

Все любят новое, на самом деле важен не результат, а исследованиеОбработать~

Спасибо за прочтение и удачи всем~

Если вы думаете, что это хорошо, поставьте большой палец вверх и вау~