var AppState = function (initialState) { this.data = initialState; this.callbacks = []; }; AppState.prototype.get = function () { return this.data; }; AppState.prototype.set = function (newState) { var merged = _.extend(this.data, newState); this.data = merged; this.callbacks.forEach(function (cb) { cb.call(null, merged); }); }; AppState.prototype.addListener = function (cb) { this.callbacks.push(cb); }; var PostsList = function (container, data) { this.container = container; this.setData(data); }; PostsList.prototype.render = function () { var ul = document.createElement('ul'); var lis = this.data.map(function (post) { var li = document.createElement('li'); li.innerText = post.title; ul.appendChild(li); }); while (this.container.hasChildNodes()) { this.container.removeChild(this.container.lastChild); } this.container.appendChild(ul); }; PostsList.prototype.setData = function (newData) { this.data = newData; this.render(); }; var Actions = { addPost: function (newPost) { var currentPosts = appState.get().posts; currentPosts.push(newPost); appState.set({ posts: currentPosts }); } }; var initialDataset = [{ title: 'My new blog post' }, { title: 'Managing state' }]; var appState = new AppState({ posts: initialDataset }); var postsList = new PostsList(document.getElementById('main'), appState.get().posts); appState.addListener(function (newData) { postsList.setData(newData.posts); }); setInterval(function () { var counter = appState.get().posts.length + 1; Actions.addPost({ title: 'Post n. ' + counter }); }, 1000);
<div id="main"></div>