JavaScript Proxy: 3 примера использования

Прокси в JavaScript применяются во многих случаях. Рассмотрим три примера, начиная с простых и переходя к более сложным.

Добавление значений по умолчанию

Функция defaultValues оборачивает входящий объект в прокси, добавляя значения по умолчанию для отсутствующих свойств.

const defaultValues = (target, defaultValue = 0) => {
  return new Proxy(target, {
    get: (obj, prop) => obj.hasOwnProperty(prop) ? obj[prop] : defaultValue
  });
};

Функция принимает целевой объект (target) и необязательное значение по умолчанию (defaultValue, по умолчанию 0). Она возвращает прокси, реализующий только метод get. Если свойство существует в объекте, возвращается его значение; иначе – значение по умолчанию.

Пример использования:

const position = defaultValues({ x: 24, y: 42 }, 0);
console.log(position); // {x: 24, y: 42}
console.log(position.z); // 0
console.log(position.someProperty); // 0

Объект position содержит координаты x и y. Обращение к несуществующим свойствам z или someProperty возвращает 0 (значение по умолчанию).

Скрытие свойств объекта

Функция hiddenProps скрывает свойства объекта, начинающиеся с указанного префикса.

const hiddenProps = (target, prefix = '_') => {
  return new Proxy(target, {
    has: (obj, prop) => obj.hasOwnProperty(prop) && !prop.startsWith(prefix),
    ownKeys: (obj) => Reflect.ownKeys(obj).filter(prop => !prop.startsWith(prefix)),
    get: (obj, prop) => obj.hasOwnProperty(prop) && !prop.startsWith(prefix) ? obj[prop] : undefined
  });
};

Функция принимает целевой объект (target) и необязательный префикс скрываемых свойств (prefix, по умолчанию ‘_’). Прокси реализует методы has, ownKeys и get. Метод has проверяет существование свойства и наличие префикса. ownKeys возвращает массив ключей без свойств с префиксом. Метод get возвращает значение свойства, если оно существует и не начинается с префикса; иначе возвращает undefined.

Пример использования:

const data = hiddenProps({ name: 'Владилен', age: 25, _id: 123 });
console.log(data); // {name: 'Владилен', age: 25}
console.log(data.name); // Владилен
console.log(data.age); // 25
console.log(data._id); // undefined
console.log(data.hasOwnProperty('_id')); // true

Свойства name и age доступны, а свойство _id — скрыто, хотя hasOwnProperty(‘_id’) возвращает true, показывая, что свойство существует в объекте.

Оптимизация поиска элементов в массиве

Класс IndexedArray оптимизирует поиск элементов в массиве по ID с помощью индексации.

class IndexedArray {
  constructor(arr) {
    this.index = {};
    arr.forEach(item => this.index[item.id] = item);
    return new Proxy(arr, {
      get: (array, prop) => {
        switch (prop) {
          case 'push':
            return (...args) => {
              const result = array[prop].call(array, ...args);
              args.forEach(item => this.index[item.id] = item);
              return result;
            };
          case 'findByID':
            return (id) => this.index[id];
          default:
            return array[prop];
        }
      }
    });
  }
}

const userData = [
  { id: 1, name: 'User1', job: 'Job1', age: 30 },
  { id: 2, name: 'User2', job: 'Job2', age: 25 },
  { id: 3, name: 'User3', job: 'Job3', age: 35 }
];
const users = new IndexedArray(userData);
console.log(users.findByID(2)); // { id: 2, name: 'User2', job: 'Job2', age: 25 }
users.push({id: 4, name: 'User4', job: 'Job4', age: 40});
console.log(users.findByID(4)); // { id: 4, name: 'User4', job: 'Job4', age: 40 }

Класс использует прокси для переопределения метода push и добавления метода findByID. Метод push добавляет элементы в массив и обновляет индекс. Метод findByID осуществляет быстрый поиск по ID, используя индекс.

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

Что будем искать? Например,программа