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 window
object as my tests tend to show ?
Clarification
Both should return only own and only enumerable properties, as we can read from the documentations:
- for-in loop with
hasOwnProperty()
: "A for...in loop only iterates over enumerable properties." andhasOwnProperty()
filters out inherited properties from the prototype chain, keeping only the own properties. Object.keys()
: "The object whose enumerable own properties are to be returned."
Conclusion: they should iterate the same keys: the enumerable and own properties only.
Browsers results
Firefox 39: no missing key
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"]
- 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"]
- 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);
if(hasOwn.call(obj, key))
prevents the inherited ones from being included in theallKeys
. And it's not that inherited properties would be missing, no, those really are own properties! – AnalogicalObject.getOwnPropertyDescriptor()
, but there doesn't appear to be anything special. – Bukharin