Running this JavaScript lists in Firefox 60.2 only one property ("location"), but there are many others, like "document.title" etc.
window.console.log("List props: " + Object.keys(window.document).sort().join(' / '));
Why is it this way? Safety? How is this done technically?
How can I list all properties?
Object.keys(o) returns the own, enumerable properties of o.
Own: properties defined directly on o, not on its prototype chain:
Enumerable: a flag that controls if a given property is included when listing an object's properties.
In this case most of the keys you expect are defined on another object in in document's prototype chain:
document.hasOwnProperty("title"); // false
document.__proto__.__proto__.hasOwnProperty("title"); // true
document.__proto__.__proto__.propertyIsEnumerable("title"); // true
You can use a for... in loop to find the enumerable properties that are defined on an object or its prototype chain:
for (let key in window.document) {
console.log(key);
}
The reason is that Object.keys() returns returns an array of strings that represent all the enumerable properties of the given object.
Try this to see which properties of document are enumerable
for(let key in document){
let isEnumerable = document.propertyIsEnumerable(key);
console.log(`docment['${key}'] isEnumerable?:${isEnumerable}`);
}
However as the previous answer has stated you can use a for-in loop to get all properties in an array sort them and join them
I couldn't find an official reason for it not working with window.document but it seems you can reproduce this behavior with other variables as well.
The issue seems to be Object.keys() not returning everything from these variables.
If you're still trying to get all properties of document, you can still use
var props = [];
for(var prop in window.document) {
props.push(prop);
}
console.log("List props: " + props.sort().join('/'));
Which will do the exact same thing as your approach.
Related
I'm having the hardest figuring out how to this (seems so simple).
I have a Javascript Object as shown here
Output of console.log(data):
{"prevExists":false,"pubKey":"b5","ID":"5f1"}
I'm trying to access the different key value pairs.
When I try the expected methods, I get back undefined.
I have tried:
var pubKey = "pubKey";
data.pubKey
data[pubkey];
data["pubKey"];
I know I'm missing something really obvious here.
You have several ways of accessing keys, depending on which keys you're talking about.
In your example, any of those would work:
var data = {
"prevExists":false,
"pubKey":"b5",
"ID":"5f1"
};
// Access all keys of enumerable string-keyed properties
Object.keys(data).forEach((key) => console.log(key,data[key]));
// Access all keys of enumerable and non-enumerable string-keyed properties
Object.getOwnPropertyNames(data).forEach((key) => console.log(key,data[key]));
// Access all keys of enumerable string-keyed properties of your object, its prototype, and all the prototype chain...
for (let key in data)
console.log(key,data[key]);
If you want to have a better understanding of what is an object's property, you can have a look at this recent answer I wrote on the topic.
You can use Object.keys and a foreach loop to access the properties on the object.
var data = {"prevExists":false,"key":"b5","ID":"5f1"};
Object.keys(data).forEach(function(key) {
console.log('key - ' + key + ' :: value - ' + data[key]);
});
First you need to create a reference to your object. Like this:
var myObj = { "prevExists": false, "key": "b5", "ID": "5f1" };
Then, you can access the elements using their keys:
console.log(myObj["prevExists"]);
Console exit:
false
Good luck!
Use the Object.keys method
var data = {"prevExists":false,"pubKey":"b5","ID":"5f1"}
console.log(Object.keys(data));
Object.keys()
The Object.keys() method returns an array of a given object's own enumerable properties, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
You are confusing yourself with the line var pubKey="pubKey".
There are 2 ways to access object parameters:
const data = {"prevExists":false,"pubKey":"b5","ID":"5f1"};
// var pubKey = "pubKey"; This line is not needed
1) data.pubKey
If you use the dot operator (.), then you reference it with the key name.
2) data["pubKey"];
If you use brackets ([]), then you use the string that matches the key.
If you add the line:
const pubKey = "pubKey";
, then data[pubKey] will also work, because it evaluates to data["pubKey"]
Run in your browser (ES5+)
var propCount = Object.keys(navigator).length;
console.log(propCount); // 0
If you do it for a plain object like that
let obj = {
foo: 'bar',
breaking: 'bad'
}
let propCount = Object.keys(obj).length;
console.log(propCount); // 2
Why does it happen?
Sorry if it might relate to another problem like when Object.keys(obj) is only counting it for simple objects which do not contain functions/arrays, but this the 1st time I encountered with it.
And would like to know the reason of it.
Object.keys() function returns properties of the object that are directly assigned to it. If you do the following:
console.log(navigator.hasOwnProperty('permissions')); // false
If you want to see properties of navigator do the following:
for(let i in navigator){
console.log(i);
}
It will list all the properties of navigator object because for ... in ... loop includes object's prototype.
That's because most properties of navigator are set on the Navigator prototype, which the navigator instance inherits, and Object.keys only returns the properties set on the navigator object itself.
You can get those properties from the prototype with this:
Object.keys(Object.getPrototypeOf(navigator));
On a side note, Firefox has the following properties in the navigator object itself:
[ "doNotTrack", "mozPay", "mozContacts", "mozApps" ]
There are enumerable and non enumerable properties in javascript. Object.keys() would return the enumerable own properties of an object. So in navigator object, it seems that there is no enumerable own properties. Hence Object.keys(navigator) is returning an empty array.
From the doc,
The Object.keys() method returns an array of a given object's own
enumerable properties, in the same order as that provided by a
for...in loop.
If you want to list out all the enumerable and non enumerable properties of a certain object, then you have to write your own logic by using Object.getOwnPropertyNames().
Note : getOwnPropertyNames will return both enum/non enum own
properties of an object.
function getAllProps(obj, props = []){
if(Object.getPrototypeOf(obj) == null){ return props; }
return getAllProps(Object.getPrototypeOf(obj),
props.concat(Object.getOwnPropertyNames(obj)));
}
console.log(getAllProps(navigator));
//This will give you all the properties.
If you use for..in loop then that will give you only the enumerable properties across the prototype chain. And you will have to miss the non enumerable properties.
I'm trying to do a bit of browser object discovery, figuring out browser built-ins etc...
I noticed different results when trying to get at the window object's properties (just FYI I'm using Chrome Version 41.0.2272.89 (64-bit)).
Object.keys(window).length;
returns 7 keys. From the docs Object.keys() returns the enumerable properties of an object.
But the docs also say that for ... in iterates over the enumerable properties of an object. However:
var i = 0;
for (var propertyName in window) {
i++;
}
returns a count of 177.
Why is this different? Shouldn't they both only be returning the count of enumerable properties?
for-in loops over the object's own enumerable properties and the enumerable properties of its prototype (and its prototype, etc.). Object.keys only lists the object's own enumerable properties.
So Object.keys builds an array something like this:
var keys = [];
var key;
for (key in object) {
if (object.hasOwnProperty(key)) { // But using an internal, non-overrideable
// operation, not literally the method
keys.push(key);
}
}
Note the hasOwnProperty check (it's not really a call to the method, it's an internal check that can't be tricked by replacing the method or similar).
I accidently used an iteration like
for (var key in arr)
{
alert(key);
}
and got an output that rose some questions. (I wanted to iterate through a JSON, so I used 'key' - an 'i' for index would be more suitable in this case, no question :-)
The first outputs were the indeces (like '0', '1' etc.) - still no question - but at last it throws the names of my Array.prototypes, I declared somewhere else in the code. Prototypes like
Array.prototype.lastIndex = function(){
return this.length - 1;
}
and it throws just 'lastIndex'.
What I don't understand: Are my own, non-inherent prototypes distinct from the JS-inherent ones like splice(), slice() ... ?
And: Why does it throw them at all? They are part of the Array.prototype, but not of a particular Array object!?
Thx in advance!
When you attach a property to an object, by default, the property will be enumerable.
If a property is enumerable, for..in will pick it up.
So, when you are iterating an array object with for..in, it first gives all the enumerable properties in the current object. Then, it goes up the prototype chain and gives all the enumerable properties of the corresponding objects. So, in your case, it goes up the chain and finds an enumerable property called lastIndex in Array's prototype, includes that in the iteration.
If you define it with enumerable: false, like this
Object.defineProperty(Array.prototype, 'lastIndex', {
value: function() {
return this.length - 1;
},
enumerable: false
});
it wont show up in for..in iterations. Quoting MDN documentation for enumerable attribute,
The enumerable property attribute defines whether the property shows up in a for...in loop and Object.keys() or not.
Note: Always use normal for loops for array iterations.
Any array instances inherits from Array.prototype. So any change to the prototype will be reflected in those array instances as well.
If you wanted it to remain only to arr you would attach the function lastIndex just to it, so other array instances won't get affected.
So it appears in for..in loop, which iterates through enumerable properties, as lastIndex is an enumerable property.
I was looking at a clone object function here:
http://jsperf.com/cloning-an-object/2
the function is:
function clone(obj) {
var target = {};
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
target[i] = obj[i];
}
}
return target;
}
and i was wondering why is the check
if (obj.hasOwnProperty(i))
needed ?
Because if property i is not in the object obj, it wouldn't be iterated in the first place in the for loop.
Am I missing something ?
The for...in construct also loops over inherited properties.
If you create an object with a constructor, for example like this :
var s = new String();
then you have all enumerable String functions listed among the properties, but not as own properties (i.e. direct properties). For example try this in the console :
for (var k in s) console.log(k)
You'll discover a few interesting functions that were probably indispensable to SO developers like formatUnicorn.
This check lets you clone direct enumerable properties without cloning the prototype properties.
See documentation on the MDN.
Because the original loop will also show properties from the prototype object, which you wouldn't want.
It's worth mentioning that as of JavaScript 1.8.5 you can use Object.keys(obj) to get an Array of properties defined on the object itself
(ones that return true for obj.hasOwnProperty(key)).
This is better (and readable) than using for-in loop.
Its supported on these browsers:
Firefox (Gecko): 4 (2.0)
Chrome: 5
Internet Explorer: 9
More info on
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys