9

In some browsers, Object.keys() doesn't return all the keys that for-in loop with hasOwnProperty() returns.

Is there a workaround without using for-in loops ?

Also is there another object than window which exhibits the same bug or is it only a problem with the windowobject as my tests tend to show ?

Clarification

Both should return only own and only enumerable properties, as we can read from the documentations:

Conclusion: they should iterate the same keys: the enumerable and own properties only.

Browsers results

  1. Firefox 39: no missing key

  2. Chromium 38: 47 missing keys:

["speechSynthesis", "localStorage", "sessionStorage", "applicationCache", "webkitStorageInfo", "indexedDB", "webkitIndexedDB", "crypto", "CSS", "performance", "console", "devicePixelRatio", "styleMedia", "parent", "opener", "frames", "self", "defaultstatus", "defaultStatus", "status", "name", "length", "closed", "pageYOffset", "pageXOffset", "scrollY", "scrollX", "screenTop", "screenLeft", "screenY", "screenX", "innerWidth", "innerHeight", "outerWidth", "outerHeight", "offscreenBuffering", "frameElement", "clientInformation", "navigator", "toolbar", "statusbar", "scrollbars", "personalbar", "menubar", "locationbar", "history", "screen"]
  1. Safari 5.1: 37 missing keys:
["open", "moveBy", "find", "resizeTo", "clearTimeout", "btoa", "getComputedStyle", "setTimeout", "scrollBy", "print", "resizeBy", "atob", "openDatabase", "moveTo", "scroll", "confirm", "getMatchedCSSRules", "showModalDialog", "close", "clearInterval", "webkitConvertPointFromNodeToPage", "matchMedia", "prompt", "focus", "blur", "scrollTo", "removeEventListener", "postMessage", "setInterval", "getSelection", "alert", "stop", "webkitConvertPointFromPageToNode", "addEventListener", "dispatchEvent", "captureEvents", "releaseEvents"]
  1. Safari 14: no missing key

Test Script

var res = (function(obj) {
    var hasOwn = Object.prototype.hasOwnProperty;

    var allKeys = [];
    for(var key in obj) {
        if(hasOwn.call(obj, key)) {
            allKeys.push(key);
        }
    }

    var keys = Object.keys(obj);

    var missingKeys = [];
    for(var i = 0; i < allKeys.length; i++) {
        if(keys.indexOf(allKeys[i]) === -1) {
            missingKeys.push(allKeys[i]);
        }
    }

    return {allKeys: allKeys, keys: keys, missingKeys: missingKeys};
})(window);

// This should be empty if the followings return the same set of keys:
// - for...in with hasOwnProperty()
// - Object.keys()
console.log(res.missingKeys, res.missingKeys.length);
Mario Varchmin
  • 3,704
  • 4
  • 18
  • 33
jlgrall
  • 1,652
  • 1
  • 13
  • 13
  • 1
    [_"The Object.keys() method returns an array of a given object's own **enumerable** properties"_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) Maybe those missing keys aren't "enumerable". – Cerbrus Jul 17 '15 at 10:13
  • @jlgrall: Then both shouldn't iterate over non-enumerable properties. – Cerbrus Jul 17 '15 at 10:22
  • @DenysSéguret: Yes, it does, but the `if(hasOwn.call(obj, key))` prevents the inherited ones from being included in the `allKeys`. And it's not that inherited properties would be missing, no, those really are own properties! – Bergi Jul 17 '15 at 10:26
  • I tried to see what could be different with `Object.getOwnPropertyDescriptor()`, but there doesn't appear to be anything special. – jlgrall Jul 17 '15 at 10:46
  • As I added a clarification, I am removing all my comments that have become no more useful. Thx. – jlgrall Jul 17 '15 at 11:32
  • Chromium gives no missing keys in version 67. – Ry- Jul 02 '18 at 16:48
  • 1
    Seems I'm getting the same issue in Node.js. The odd thing is that I'm getting some non-enumerable keys, and the one enumerable key (of many) I want is missing. Did you ever find a resolve to your woes? – Guy Park Oct 21 '18 at 11:32
  • It is weird to blame different browsers have different result for "window" object - it is not best test sample – sonnenhaft Nov 28 '19 at 03:43
  • Safari 14: no missing key – Mario Varchmin Jul 16 '21 at 10:21

0 Answers0