20.2.5. Реализация хранилища на основе cookies

Пример 20.2 демонстрирует, как поверх cookies можно реализовать методы, имитирующие прикладной интерфейс объекта Storage. Передайте конструктору СоokieStorage() желаемые значения атрибутов max-age и path и используйте получившийся объект подобно тому, как вы использовали бы localStorage или sessionStorage. Однако имейте в виду, что этот пример не реализует событие «storage» и не выполняет автоматическое сохранение или извлечение значений при записи или чтении свойств объекта CookieStorage.

Пример 20.2. Реализация интерфейса объекта Storage на основе cookies

/*

* CookieStorage.js

* Этот класс реализует прикладной интерфейс объекта Storage, на который ссылаются

* свойства localStorage и sessionStorage, но поверх HTTP Cookies.

*/

function CookieStorage(maxage, path) { // Аргументы определяют срок хранения

                                       // и область видимости

                                       // Получить объект, хранящий все cookies

var cookies = (function() {   // Функция getCookies(), реализованная выше

  var cookies = {};           // Возвращаемый объект

  var all = document.cookie;  // Получить все cookies в одной строке

  if (all === "")   // Если получена пустая строка

    return cookies; // вернуть пустой объект

  var list = all.split(";”); // Разбить на пары имя/значение

  for(var і = 0; і < list.length; i++) { // Для каждого cookie

    var cookie = list[і]:

    var p = cookie.indexOf("=");       // Отыскать первый знак =

    var name = cookie, substrings, p); // Получить имя cookie

    var value = cookie.substring(p+1); // Получить значение cookie

    value = decodeURIComponent(value); // Декодировать значение

    cookies[name] = value;             // Сохранить имя и значение

  }

  return cookies;

}());

// Собрать имена cookies в массиве

var keys = [];

for(var key in cookies) keys.push(key);

// Определить общедоступные свойства и методы Storage API

// Количество хранящихся cookies

this.length = keys.length; *

// Возвращает имя n-го cookie или null, если n вышло за диапазон индексов

this.key = function(n) {

  if (n < О И n >= keys.length) return null;

  return keys[n];

};

// Возвращает значение указанного cookie или null,

this.getltem = function(name) { return cookies[name] || null; };

// Сохраняет значение

this.setltem = function(key, value) {

  if (!(key in cookies)) { // Если cookie с таким именем не существует

    keys.push(key);        // Добавить ключ в массив ключей

    this.length++;         // И увеличить значение length

  }

  // Сохранить пару имя/значение в множестве cookies.

  cookies[key] = value;

  // Установить cookie.

  // Предварительно декодировать значение и создать строку

  // имя=кодированное-значение

  var cookie = key + "=" + encodeURIComponent(value);

  // Добавить в строку атрибуты cookie

  if (maxage) cookie += "; max-age=" + maxage;

  if (path) cookie += "; path=" + path;

  // Установить cookie с помощью свойства document.cookie

  document.cookie = cookie;

}

// Удаляет указанный cookie

this.removeItem = function(key) {

  if (!(key in cookies)) return; // Если не существует, ничего не делать

  // Удалить cookie из внутреннего множества cookies

  delete cookies[key];

  // И удалить ключ из массива имен.

  // Это легко можно было бы сделать с помощью метода indexOf() массивов,

  // определяемого стандартом ES5.

  for(var і = 0; і < keys.length; i++) { // Цикл по всем ключам

    if (keys[i] === key) { // При обнаружении ключа

      keys.splice(i,1); // Удалить его из массива,

      break;

    }

  }

  this.length--; // Уменьшить значение length

  // Наконец фактически удалить cookie, присвоив ему пустое значение

  // и истекший срок хранения.

  document.cookie = key + "=; max-age=0";

};