JavaScript objects aren't hash tables, and on a modern engine hash tables are only used in their implementation if you delete properties from them. Otherwise, they're instances of highly-optimized runtime-generated classes. None of which really matters to the problem at hand. :-)
Assuming you want an ongoing link between the 0 property and one of the named properties, there's just no way to do this in ES5 and earlier. Instead, you'll need getter/setter methods for the indexed access:
Object.defineProperty(foo, "item", {
    value: function(index, value) {
        var key = Object.keys(this).sort(orderingFunction)[index];
        if (arguments.length < 2) {
            // Getter
            return this[key];
        }
        // Setter
        this[key] = value;
        return this;
    }
});
...where orderingFunction is the function that defines your concept of the order of the keys. (In ES5 and below, properties had no order. While in ES2015 and above properties do have an order, it's A) Not useful, and B) Not guaranteed to be the order returned by Object.keys.)
Usage:
foo.item(0); // "value"
foo.item(0, "new value");
Or if you prefer, use separate functions for the getter and setter.
Note that this is fairly expensive, what with all that sorting.
There is a way to do it in ES2015 and above: a Proxy object, which can do two key things here:
- Implement a default property access function that you can use for numeric access 
- Allow you to maintain your keys array without having to constantly re-sort it 
// REQUIRES ES2015+ SUPPORT IN YOUR BROWSER
let foo = {
  question: "Life, the Universe, and Everything!",
  answer: 42
};
let rexNumber = /^\d+$/;
let fooProxy = indexedProxy(foo);
console.log(fooProxy[0]); // 42
fooProxy.answer = 67;
console.log(fooProxy[0]); // 67
fooProxy.bar = "foo";
console.log(fooProxy[1]); // "foo"
function indexedProxy(obj) {
  // An array of the current keys
  let keys = getKeys(foo);
  // Return the proxy
  return new Proxy(obj, {
    // Called when any property is gotten from the target
    get(target, property) {
      if (rexNumber.test(property)) {
        // Indexed access
        let key = keys[property];
        return key === undefined ? undefined : target[key];
      }
      // Normal access
      return target[property];
    },
    // Called when any property is set on the target
    set(target, property, value) {
      if (rexNumber.test(property)) {
        // Indexed access
        let key = keys[property];
        if (key === undefined) {
          throw new Error(`No property for index #{property}`);
        }
        target[key] = value;
      } else {
        // Normal access, do we know the key?
        let newProp = !keys.includes(property);
        target[property] = value;
        if (newProp) {
          // Rebuild our array
          keys = getKeys(target);
        }
      }
    }
  });
}
function getKeys(obj) {
  // Let's go for alphabetical
  return Object.keys(obj).sort((a, b) => a.localeCompare(b));
}
 
 
Proxies are also not cheap, but hopefully would perform better than an array you constantly have to generate and sort.
Obviously the above is just an example, not a highly-optimized general-purpose tool. It doesn't use the correct definition of an array index (details buried in this answer), it uses a simpler "is it all digits?" definition. It only handles an objects own, enumerable properties; if you want to handle inherited properties or ones marked non-enumerable, that's possible, it just needs tweaking thea above.