An alternative recursive implementation. I just felt like writing one implementation myself, even though the current ones are already really good.
The recursive function checks whether the key is of type 'object'.
- If it's an object, we iterate by each object's key.
- Else, we add it into our result object.
function flat(res, key, val, pre = '') {
  const prefix = [pre, key].filter(v => v).join('.');
  return typeof val === 'object'
    ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
    : Object.assign(res, { [prefix]: val});
}
return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
Flat NPM package
Or you can simply use flat npm package, which is a well known tested library.
var flatten = require('flat')
flatten(obj);
⬑ I would use this in serious code.
[Extra] Neater call to the function above
function flatObject(input) {
  function flat(res, key, val, pre = '') {
    const prefix = [pre, key].filter(v => v).join('.');
    return typeof val === 'object'
      ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
      : Object.assign(res, { [prefix]: val});
  }
  return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
}
const result = flatObject(input);
[Extra] Demo
http://codepen.io/zurfyx/pen/VpErja?editors=1010
function flatObject(input) {
  function flat(res, key, val, pre = '') {
    const prefix = [pre, key].filter(v => v).join('.');
    return typeof val === 'object'
      ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
      : Object.assign(res, { [prefix]: val});
  }
  return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
}
const result = flatObject({
    a: 'jack',
    b: {
        c: 'sparrow',
        d: {
           e: 'hahaha'
        }
    }
});
document.getElementById('code').innerHTML = JSON.stringify(result, null, 2);
<pre><code id="code"></code></pre>