Рубрики
Без рубрики

Введение в прокси JavaScript в ES6

Прокси имеют возможность изменить фундаментальное поведение объектов и функций. В этой статье мы поговорим о прокси JavaScript, представленные в ES6 и демонстрируют их функциональность.

Автор оригинала: Janith Kasun.

Вступление

В этой статье мы будем говорить о JavaScript Proxies которые были введены с версией JavaScript Ecmascript 6 (ES6). Мы будем использовать некоторые из существующих синтаксиса ES6, включая Оператор распространения в этой статье. Так что будет полезно, если у вас есть несколько базовых знаний о ES6.

Что такое прокси?

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

До появления прокси не было введено, у нас не было доступа родного уровня, чтобы изменить фундаментальное поведение объекта, ни функции. Но с ними у нас есть возможность действовать в качестве среднего слоя, чтобы изменить доступ к объекту, генерировать такую информацию, как, сколько раз вызывалось функция и т. Д.

Пример прокси недвижимости

Начнем с простого примера, чтобы увидеть прокси в действии. Чтобы начать, давайте создадим объект человека с Имя , фамилия и возраст характеристики:

const person = {
    firstName: 'John',
    lastName: 'Doe',
    age: 21
};

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

Давайте сначала создадим объект обработчика:

const handler = {
    get(target, property) {
        console.log(`you have read the property ${property}`);
        return target[property];
    }
};

Вот как вы можете создать простой прокси:

const proxyPerson = new Proxy(person, handler);

console.log(proxyPerson.firstName);
console.log(proxyPerson.lastName);
console.log(proxyPerson.age);

Запуск этого кода должен давать:

you have read the property firstName
John
you have read the property lastName
Doe
you have read the property age
21

Каждый раз, когда вы получите доступ к собственности этого прокси-объекта, вы получите консольное сообщение с именем свойства. Это очень простой пример прокси JavaScript. Поэтому, используя этот пример, давайте познакомимся с несколькими терминами.

Цель прокси

Первый параметр цель Это объект, который вы прикрепили прокси. Этот объект будет использоваться прокси-сервером для хранения данных, что означает, что если вы измените значение целевого объекта, значение прокси-объекта также изменится.

Если вы хотите избежать этого, вы можете пройти цель Непосредственно к прокси в качестве анонимного объекта, или вы можете использовать некоторые метод инкапсуляции, чтобы защитить исходный объект, создавая немедленно вызываемую функциональную экспрессию (IIFIFE) или Singleton.

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

Изменение оригинального целевого объекта все еще отражено в прокси:

console.log(proxyPerson.age);
person.age = 20;
console.log(proxyPerson.age);
you have read the property age
21
you have read the property age
20

Proxy Handler

Второй параметр для Прокси Конструктор – это обработчик , что должно быть объектом, содержащим методы, которые описывают способ, которым вы хотите контролировать цель поведение. Методы внутри этого обработчика, например Получить () Метод называется Ловушки Отказ

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

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

Прокси-ловушки

Ловушка Get ()

Получить () Ловушки пожали, когда кто-то пытается получить доступ к конкретной собственности. В предыдущем примере мы использовали это, чтобы распечатать предложение, когда доступен недвижимость.

Как вы уже можете знать, JavaScript не поддерживает частные свойства. Поэтому иногда как конвенция, разработчики используют подчеркивание ( _ ) перед именем свойства, например, _SecurityNumber , чтобы определить его как частную собственность.

Однако это на самом деле не соблюдает что-либо на уровне кода. Разработчики просто знают, что они не должны напрямую доступа к свойствам, которые начинаются с _ Отказ С прокси, мы можем изменить это.

Давайте обновим наше человек Объект с номером социального страхования в недвижимости под названием _ssn :

const person = {
    firstName: 'John',
    lastName: 'Doe',
    age: 21,
    _ssn: '123-45-6789'
};

Теперь давайте редактируем Получить () Ловушка, чтобы бросить исключение, если кто-то пытается получить доступ к недвижимости, который начинается с подчеркивания:

const handler = {
    get(target, property) {
        if (property[0] === '_') {
            throw new Error(`${property} is a private property`);
        }

        return target[property];
    }
}

const proxyPerson = new Proxy(person, handler);

console.log(proxyPerson._ssn);

Если вы запускаете этот код, вы должны увидеть следующее сообщение об ошибке на вашей консоли:

Error: _ssn is a private property

Набор () ловушка

Теперь давайте посмотрим на Установить () Ловушка, которая контролирует поведение при настройке значений в свойстве целевого объекта. Чтобы дать вам четкий пример, давайте предположим, что когда вы определяете человек Объединить значение возраст должно быть в диапазоне 0 к 150 Отказ

Как вы уже знаете, JavaScript является динамическим языком ввода, что означает, что переменная может удерживать любой тип значения (строка, номер, лол и т. Д.) В любой момент времени. Так что обычно это очень трудно обеспечить укрепление возраст недвижимость, чтобы просто держать целые числа. Однако с прокси, мы можем контролировать способ, которым мы устанавливаем значения для свойств:

const handler = {
    set(target, property, value) {
        if (property === 'age') {
            if (!(typeof value === 'number')) {
                throw new Error('Age should be a number');
            }

            if (value < 0 || value > 150) {
                throw new Error("Age value should be in between 0 and 150");
            }
        }

        target[property] = value;
    }
};

const proxyPerson = new Proxy(person, handler);
proxyPerson.age = 170;

Как вы можете видеть в этом коде, Установить () Ловушка принимает три параметра, которые являются:

  • цель : Целевой объект, который прокси прикреплен к
  • Недвижимость : Имя объекта свойства
  • ценность : Значение, которое присваивается собственности

В этой ловушке мы проверили, если имя недвижимости возраст И если да, если это тоже номер и значение, составляет от 0 до 150 – бросая ошибку, если она не.

Когда вы запускаете этот код, вы должны увидеть следующее сообщение об ошибке на консоли:

Error: Age value should be in between 0 and 150

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

Ловушка deleteproperty ()

Теперь давайте перейдем к deleteproperty () Ловушка, которая будет вызвать, когда вы пытаетесь удалить свойство от объекта:

const handler = {
    deleteProperty(target, property) {
        console.log('You have deleted', property);
        delete target[property];
    }
};

const proxyPerson = new Proxy(person, handler);

delete proxyPerson.age;

Как вы можете видеть, deleteproperty () Ловушка также принимает цель и Недвижимость Параметры.

Если вы запускаете этот код, вы должны увидеть следующий вывод:

You have deleted age

Использование прокси с функциями

Применить () ловушку

Применить () Ловушка используется для идентификации при вызове функции на объекте прокси. Прежде всего, давайте создадим человека с именем и фамилию:

const person = {
    firstName: 'Sherlock',
    lastName: 'Holmes'
};

Затем способ получить полное имя:

const getFullName = (person) => {
    return person.firstName + ' ' + person.lastName;
};

Теперь давайте создадим метод прокси, который преобразует вывод функции в прописные буквы, предоставив Применить () Ловушка внутри нашего обработчика:

const getFullNameProxy = new Proxy(getFullName, {
    apply(target, thisArg, args) {
        return target(...args).toUpperCase();
    }
});

console.log(getFullNameProxy(person));

Как вы можете видеть в настоящем примере кода, Применить () Ловушка будет называться, когда функция называется. Это принимает три параметра – цель , thisarg (который является это аргумент для вызова), а также args , который является список аргументов, переданных в функцию.

Мы использовали Применить () Ловушка Для выполнения целевой функции с заданными аргументами с использованием синтаксиса ES6 Spread и преобразована результат в верхний регистр. Таким образом, вы должны увидеть верхнее имя:

SHERLOCK HOLMES

Вычисленные свойства с прокси

Вычисленные свойства являются свойствами, которые рассчитываются путем выполнения операций по другим существующим свойствам. Например, скажем, у нас есть человек объект с свойствами Имя и фамилия Отказ С этим полное имя может быть сочетанием этих свойств, как и в нашем последнем примере. Таким образом, полное имя – это Расчетное свойство Отказ

Во-первых, давайте снова создадим человек Объект с именем и фамилией:

const person = {
    firstName: 'John',
    lastName: 'Doe'
};

Тогда мы можем создать обработчик с Получить () Ловушка для возврата расчетного полного имени, которое достигается путем создания прокси человек :

const handler = {
    get(target, property) {
        if (property === 'fullName') {
            return target.firstName + ' ' + target.lastName;
        }

        return target[property];
    }
};

const proxyPerson = new Proxy(person, handler);

Теперь давайте попробуем доступ к полному имени Proxy Person:

console.log(proxyPerson.fullName);
John Doe

Используя только прокси, который мы создали метод «Getter» на человек объект без необходимости на самом деле изменить сам оригинальный объект.

Теперь давайте посмотрим другой пример, который более динамичен, чем мы столкнулись с далеко. На этот раз вместо возврата всего лишь свойство, мы вернем функцию, которая динамически создана на основе заданного имени функции.

Рассмотрим массив людей, где каждый объект имеет ID человека, имя человека и возраст человека. Нам нужно запрашивать человека по ID , Имя или возраст Отказ Так что просто мы можем создать несколько методов, GetByid , getbyname и GetByage Отказ Но на этот раз мы будем делать вещи несколько дальше.

Мы хотим создать обработчик, который может сделать это для массива, который может иметь любое свойство. Например, если у нас есть массив книг, и в каждой книге есть недвижимость ISBN Мы также должны быть в состоянии запросить этот массив, используя getbyisbn И метод должен быть динамически генерирован на время выполнения.

Но на данный момент давайте создадим массив людей.

const people = [
    {
        id: 1,
        name: 'John Doe',
        age: 21
    },
    {
        id: 2,
        name: 'Ann Clair',
        age: 24
    },
    {
        id: 3,
        name: 'Sherlock Holmes',
        age: 35
    }
];

Теперь давайте создадим получить Ловушка для генерации динамической функции в соответствии с именем функции.

const proxyPeople = new Proxy(people, {
    get(target, property) {
        if (property.startsWith('getBy')) {
            let prop = property.replace('getBy', '')
                               .toLowerCase();

            return function(value) {
                for (let i of target) {
                    if (i[prop] === value) {
                        return i;
                    }
                }
            }
        }

        return target[property];
    }
});

В этом коде мы впервые проверяем, начинается ли имя свойства с «getby», то мы убираем «getby» из имени свойства, поэтому мы заканчиваем фактическое имя свойства, которое мы хотим использовать для запроса элемента. Так, например, если имя свойства – GetByid Мы в конечном итоге с ID как свойство запрошению.

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

Вы можете попробовать это, выполнив следующее:

console.log(proxyPeople.getById(1));
console.log(proxyPeople.getByName('Ann Clair'));
console.log(proxyPeople.getByAge(35));

Соответствующий объект человека для каждого вызова должен быть показан на консоли:

{ id: 1, name: 'John Doe', age: 21 }
{ id: 2, name: 'Ann Clair', age: 24 }
{ id: 3, name: 'Sherlock Holmes', age: 35 }

В первой линии мы использовали proxypeople.getbyId (1) , который затем вернул пользователь с помощью ID из 1. Во второй линии мы использовали Proxypeople.getbyname («Ann Clair») , который вернул человека с именем «Энн Клэр», и так далее.

Как упражнение для читателя, попробуйте создать собственный массив книги со свойствами ISBN , Название и Автор Отказ Затем, используя аналогичный код, как указано выше, посмотрите, как вы можете использовать getbyisbn , GetByTitle и GetbyAuthor Чтобы получить элементы из списка.

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

Заключение

Исходный код для этой статьи доступен на Github по-прежнему. Используйте это, чтобы сравнить свой код, если вы застряли вдоль учебника.