Pull to refresh

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

JavaScript *
Awaiting invitation

Про куки


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


$.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);
    }
}

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

Tags:
Hubs:
You can’t comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.