Edit in JSFiddle

// This code uses ES2015.
// Please use a compatible browser like: Chrome, Opera, Firefox

function Seer (dataObj) {
  let signals = {}

  observeData(dataObj)

  return {
    data: dataObj,
    observe,
    notify
  }

  function observe (property, signalHandler) {
    if(!signals[property]) signals[property] = []

    signals[property].push(signalHandler)
  }

  function notify (signal) {
    if(!signals[signal] || signals[signal].length < 1) return

    signals[signal].forEach((signalHandler) => signalHandler())
  }

  function makeReactive (obj, key) {
    let val = obj[key]

    Object.defineProperty(obj, key, {
      get () {
        return val
      },
      set (newVal) {
        val = newVal
        notify(key)
      }
    })
  }

  function observeData (obj) {
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        makeReactive(obj, key)
      }
    }
    // We can safely parse the DOM looking for bindings after we converted the dataObject.
    parseDOM(document.body, obj)
  }

  function syncNode (node, observable, property) {
    node.textContent = observable[property]
    // We remove the `Seer.` as it is now available for us in our scope.
    observe(property, () => node.textContent = observable[property])
  }

  function parseDOM (node, observable) {
    const nodes = document.querySelectorAll('[s-text]')

    for (const node of nodes) {
      syncNode(node, observable, node.attributes['s-text'].value)
    }
  }
}

const App = Seer({
  title: 'Game of Thrones',
  firstName: 'Jon',
  lastName: 'Snow',
  age: 25
})

function updateText (property, e) {
	App.data[property] = e.target.value
}

function resetTitle () {
	App.data.title = "Game of Thrones"
}
<h1 s-text="title"></h1>
<div class="form-inline">
  <div class="form-group">
    <label for="title">Title: </label>
    <input 
      type="text" 
      class="form-control" 
      id="title" placeholder="Enter title"
      oninput="updateText('title', event)">
  </div>
  <button class="btn btn-default" type="button" onclick="resetTitle()">Reset title</button>
</div>

              

External resources loaded into this fiddle: