Какие в JS есть решения хранения данных, которые доступных из любого места приложения?
Пишу скрипт на нативном JS, где нужные данные появляются в функции некоторого уровня вложенности, но должны быть доступными из любого уровня вложенности.
Среди моих познаний JS только один вариант реализации - хранить в localStorage.
То есть я помещаю данные в localStorage:
localStorage.setItem('answer', JSON.stringify(answer));
а потом забираю их оттуда:
localStorage.getItem("answer");
Говорят, localStorage синхронный, то есть останавливающий работу остальных скриптов пока сам выполняется. Наверняка есть ещё какие-то подводные камни. Мне даже не нужно хранить данные сессии; я их даже вынужденно удаляю при загрузке страницы. Более того меня не покидает чувство, что решение хранить промежуточные данные через localStorage - не изящное, и есть куда более профессиональное.
Есть возможность создать какое-то хранилище (массив, объект или ещё что-то), куда можно и записать, и считать данные, не использую localStorage? Например, данные появляются на 10-ом уровне вложенности, но доступны из любого места приложения?
ПС. Мне кажется, что решение прям очень простое, из азов JS, я прав?
Ответы (2 шт):
Думаю в Вашем случае подойдет глобальная переменная:
window.STORAGE = {}
console.log(STORAGE)
// {}
STORAGE.data = 10101010
console.log(STORAGE)
// {
// "data": 10101010
// }
В последней версии ECMAScript появилась возможность универсального обращения к глобальным объектам glabalThis:
// браузер
window
// nodejs
global
// web-worker
self
Теперь мы можем удобно обращаться к нему, не беспокоясь о том что нужно менять window на global или self, если например нужно запустить скрипт на Node или WebWorker соответственно:
globalThis.STORAGE = {}
console.log(STORAGE)
// {}
STORAGE.data = 10101010
console.log(STORAGE)
// {
// "data": 10101010
// }
Если нужно что более "серьезное", то стоит посмотреть в сторону Redux.
Если такой объект всего один, можно банально создать глобальную константу в самом начале программы и использовать его как связывающее звено между разными функциями. Скажем:
const ROOT = {};
(function() {
let colors = ["#b22", "#382", "#17a"];
let i = 0;
ROOT.next_color = function() {
return colors[ i = (i + 1) % colors.length ];
};
})();
(function() {
document.addEventListener("click", function() {
document.body.style.backgroundColor = ROOT.next_color();
});
})();
« Клик »
При этом, если таких переменных станет многовато, это ничем не лучше использования обычных глобальных переменных. Захочется как-то группировать общие переменные в дополнительные вложенные объекты, чтобы случайно названия не пересекались.
Во время писанины мелкой браузерной игрушки, появилась необходимость пары десятка подобных объектов (классов). Везде таскать с собой "приставку" типа ROOT.animate.add(), ROOT.battle - не очень удобно. Как вариант - можно было в отдельном файле заранее глобально объявить все такие объекты, и уже в другом месте их заполнять.
Другой вариант (был принят как финальный), из каждой "папки" объявить свой глобальный объект через window. А чтобы не париться с вызовами функций, которые еще не созданы, сначала происходит объявление всех необходимых объектов и функций, а отдельная финальная функция управляет их запуском, около того:
// файл
window.BUBU = {
say: function(str) {
alert(str);
MOO.say("moo");
},
};
// другой файл
window.MOO = { // Если здесь объявить const MOO вместо window,
// из BUBU он не будет виден, выдаст ошибку.
i: 0,
say: function(str) {
alert(str);
if (this.i++ < 4) BUBU.say("bubu");
},
};
//***
BUBU.say("Начали!");
Такой подход как минимум работает, пока таких объектов - 10-20, для пары десятка тысяч строк кода. С бОльшими объемами не работал - не знаю)