How to fix missing keys in Object.keys() compared to for...in with hasOwnProperty()
Asked Answered
B

0

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);
Bukharin answered 17/7, 2015 at 10:4 Comment(9)
"The Object.keys() method returns an array of a given object's own enumerable properties" Maybe those missing keys aren't "enumerable".Extern
@jlgrall: Then both shouldn't iterate over non-enumerable properties.Extern
@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!Analogical
I tried to see what could be different with Object.getOwnPropertyDescriptor(), but there doesn't appear to be anything special.Bukharin
As I added a clarification, I am removing all my comments that have become no more useful. Thx.Bukharin
Chromium gives no missing keys in version 67.Chunk
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?Sovran
It is weird to blame different browsers have different result for "window" object - it is not best test sampleDozer
Safari 14: no missing keyLabiovelar

© 2022 - 2024 — McMap. All rights reserved.