function createStore(reducer){ let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined let cbs = [] //массив подписчиков const getState = () => state //функция, возвращающая переменную из замыкания const subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка const dispatch = action => { const newState = reducer(state, action) //пробуем запустить редьюсер if (newState !== state){ //проверяем, смог ли редьюсер обработать action state = newState //если смог, то обновляем state for (let cb of cbs) cb() //и запускаем подписчиков } } return { getState, //добавление функции getState в результирующий объект dispatch, subscribe //добавление subscribe в объект } } function reducer(state, {type, ШО, СКОКА}){ //объект action деструктуризируется на три переменных if (!state){ //начальная уборка в ларьке: return { пиво: 100, //{count: 100, price: 30} чипсы: 100,//{count: 100, price: 25} сиги: 100, // касса: 0, при покупках увеличивается } } if (type === 'КУПИТЬ'){ //если тип action - КУПИТЬ, то: //проверить на: //наличие товара как такового (есть ли ключ в объекте) //количество денег в action //наличие нужного количества товара. //и только при соблюдении этих условий обновлять state. return { ...state, //берем все что было из ассортимента [ШО]: state[ШО] - СКОКА //и уменьшаем то, что покупается на количество } } return state //если мы не поняли, что от нас просят в `action` - оставляем все как есть } const store = createStore(reducer) //надо бы напилить цикл, который в select напихивает ассортимент. //возможно, если вы собираетесь выводить (и обновлять) количество, //это надо делать где в subscribe, иначе оно не будет обновлять количество let select = document.getElementById('goods') for(let key in store.getState()) { let option = document.createElement('option') option.innerText = key option.value = key select.append(option) } let quantity = document.getElementById('quantity') const купи = (ШО, СКОКА) => ({type: 'КУПИТЬ', ШО, СКОКА}) buy.onclick = () => { //достает выбранный товар и количество из DOM // store.dispatch(купи(....,....)) store.dispatch(купи(select.value, quantity.value)) console.log('steit', store.getState()) } //запомнит функцию во внутреннем массиве cbs. //она будет запущена при любом успешном dispatch const unsubscribe = store.subscribe(() => console.log(store.getState())) //setTimeout(unsubscribe, 10000) //отпишемся через 10 секунд, например //происходит запуск редьюсера, который создает новый state. //dispatch запускает всех подписчиков из массива cbs let table = document.createElement('table') table.border = 1 function smth(){ table.innerHTML = '' for(let key in store.getState()) { let tr = document.createElement('tr') let tdKey = document.createElement('td') let tdValue = document.createElement('td') tdKey.innerText = key tdValue.innerText = store.getState()[key] tr.append(tdKey, tdValue) table.append(tr) } shop.append(table) } smth() store.subscribe(smth) //setTimeout(() => store.dispatch({type: 'КУПИТЬ', ШО: 'пиво', СКОКА: 3}), 5000) console.log(store.getState())