Proxy как шаблон проектирования на примере работы с куками

Про куки


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


$.cookie('cookie_name', 'cookie_value'); //установка
$.cookie('cookie_name'); //чтение
$.cookie('cookie_name', null); //удаление
$.cookie('cookie_name', 'cookie_value', {
    expires: 5,
    path: '/admin',
}); //опции

или


cookie.set('cookie_name', optios);
cookie.get('cookie_name');

В исходниках на получение куки всегда есть что-то из разряда


var cookies = document.cookie.split('; ');
for (var i = 0; i < cookies.length; i++) {
// и разбор самой куки
}

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


// прочитать
if (cookie.id === '1') {
    //удалить
    delete cookie.id;
}

//установить новое значение
cookie.key = '12341234';

//поменяем опции
cookie.options = {
    expires: new Date(Date.now() + 30*24*60*60*1000).toUTCString(),
    path: '/'
};

//обновить значение
cookie.key = '43214321';

Proxy


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


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


class Cookie {
    /**
    * @param {Object} [defaultOptions] - не обязательный параметр опций
    */
    constructor(defaultOptions) {
        //приватная переменная, храним опции
        let _options;

        //создаем геттер и сеттер на поле options у нашего класса
        Object.defineProperty(this, 'options', {
            get() {
                return _options;
            },
            set(v) {
                //установить в опции можем только объект
                if (v instanceof Object) {
                    _options = v;
                }
            }
        });

        //инициализируем опции куков по умолчанию 
        if (defaultOptions instanceof Object) {
            _options = defaultOptions;
        } else {
            _options = {
                expires: new Date(Date.now() + 30*24*60*60*1000).toUTCString()
            };
        }

        //конфигурация Proxy для работы с нашем классом
        let handler = {
            //сработает при обращении к свойству класса
            get(target, prop) {
                //target - наш класс
                //prop - имя свойства
                return target[prop];
            },
            //сработает при установки свойства класса
            set(target, prop, value) {
                //target - наш класс
                //prop - имя свойства
                //value - значение свойства

                //так мы можем контролировать установку свойства
                //так как в нашем примере такой параметр системный
                //просто установим значение в опции
                if (prop === 'options') {
                    target.options = value;
                    return;
                }

                //с куками работаем как с текстом
                target[prop] = String(value);
                let updatedCookie = prop + '=' + encodeURIComponent(value);

                for (var key in _options) {
                    updatedCookie += `; ${key}=${_options[key]}`;
                }
                document.cookie = updatedCookie;
            },
            //вызывается при удалении свойства
            deleteProperty(target, prop) {
                document.cookie = `${prop}=''; path=${
                _options.path?_options.path:'/'}; expires=${
                new Date().toUTCString()}`;
                //результат удаления вернем, 
                //при попытки удалить свойство options будет ошибка
                return delete target[prop];
            }
        };

        //прочитаем все куки и установим их в кэш
        document.cookie.split('; ').forEach(v => {
            v = v.split('=');
            this[v[0]] = decodeURIComponent(v[1]);
        });

        //создаем объект прокси и возвращаем его
        return new Proxy(this, handler);
    }
}

Ссылка на код, хорошего Вам дня!

Метки:
https://developer.mozilla.org/ru