Массивы JavaScript - это коллекции элементов, каждый из которых доступен через индекс. Эти индексы являются неотрицательными целыми числами, и доступ к отрицательному индексу просто вернет undefined.

// JavaScript:
const letters = ['a', 'b', 'c', 'd', 'e'];
letters[0]; // => 'a'
letters[2]; // => 'c'
letters[-1]; // => undefined

В других языках программирования, например Python, мы можем использовать отрицательные индексы для доступа к элементам с конца массива:

# Python:
letters = ['a', 'b', 'c', 'd', 'e'];
letters[0]; // => 'a'
letters[-1]; // => 'e'

По умолчанию такое поведение недоступно для JavaScript. Вместо этого мы должны написать подробный код, чтобы получить последний элемент массива, например:

// JavaScript:
const letters = ['a', 'b', 'c', 'd', 'e'];
letters[letters.length - 1]; // => 'e'

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

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

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

Однако сила прокси-серверов заключается в способности определять ловушки. Ловушки - это методы, которые фиксируют операции с прокси-объектом (такие как установка / получение значений свойств, удаление свойства и т. Д.) И позволяют нам определять настраиваемое поведение для этих операций.

Создание прокси

Мы можем создать прокси-объект с помощью конструктора Proxy:

const proxy = new Proxy(letters, {});

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

Определение нашей первой ловушки

При доступе к элементу массива с использованием отрицательного индекса, такого как proxy[-1], мы пытаемся «получить» свойство с именем «-1» в нашем целевом массиве. По умолчанию это просто возвращает undefined. Но поскольку мы уже обернули этот массив в прокси-объект, теперь мы можем определить ловушку get для настройки поведения «получить свойство».

const proxy = new Proxy(letters, {
    get(target, prop) {
        return target[prop];
    }
});

В метод get trap передается целевой объект и свойство, к которому мы пытаемся получить доступ. Какое бы значение мы ни возвращали из этого метода, оно становится значением, возвращаемым тому, кто пытался получить к нему доступ.

Обработка отрицательных индексов массива

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

const proxy = new Proxy(letters, {
    get(target, prop) {
        if (!isNaN(prop)) {
            prop = parseInt(prop, 10);
            if (prop < 0) {
                prop += target.length;
            }
        }
        return target[prop];
    }
});

Здесь мы проверяем, является ли свойство, к которому мы пытаемся получить доступ, числом (кстати, числовые имена свойств, такие как индексы массивов, преобразуются в строки при передаче в ловушку get) и является ли оно отрицательным. Если да, мы преобразуем его в допустимое значение индекса массива и возвращаем элемент массива по этому вычисленному индексу. После этого мы теперь можем использовать отрицательные индексы для проксируемых массивов:

const letters = ['a', 'b', 'c', 'd', 'e'];
const proxy = new Proxy(letters, {
    get(target, prop) {
        if (!isNaN(prop)) {
            prop = parseInt(prop, 10);
            if (prop < 0) {
                prop += target.length;
            }
        }
        return target[prop];
    }
});
proxy[0]; // => 'a'
proxy[-1]; // => 'e'
proxy[-2]; // => 'd'

Что дальше?

В этой статье мы едва коснулись того, на что способны прокси JavaScript. Мы рассмотрели ловушку get, которая позволяет нам настраивать поведение при получении свойства из проксируемого объекта.

Прокси-серверы поддерживают множество других ловушек, таких как установка или удаление свойства, проверка существования свойства, вызов цели в качестве конструктора и т. Д. Ознакомьтесь с его документацией на MDN, чтобы узнать о них больше.

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

Недавно мы начали небольшой побочный проект под названием rbjs, который пытается реализовать методы массива Ruby в JavaScript. Под капотом мы используем прокси для дополнения массивов JS дополнительными методами без изменения его прототипа. Мы действительно просто ищем повод использовать прокси для чего-то 😆. Пожалуйста, проверьте это и не стесняйтесь вносить свой вклад, спасибо!



Спасибо, что прочитали эту статью! Не стесняйтесь оставлять свои комментарии и дайте нам знать, что вы думаете. Мы - группа разработчиков, которые любят создавать случайные вещи и иногда писать о технологиях. Ознакомьтесь с нашими другими статьями и некоторыми нашими проектами. Хорошего дня! ❤️