1

I have some JavaScript running in Chrome using the Geolocation API:

navigator.geolocation.watchPosition((pos) => {
    console.log(pos.coords);
    console.log(Object.keys(pos.coords);

  }, (err) => {
    alert('Geolocation error.\n' + err.message);

  }, {
    enableHighAccuracy: true
  });

When Chrome detects a change in location, it fires off the first callback. This is working well.

The problem comes when I try to do something with that data. When the callback is fired, on my console I will first be able to see the Coordinates object where I called console.log(pos.coords):

Coordinates {latitude: 5.520007, longitude: 13.404954, altitude: null, accuracy: 150, altitudeAccuracy: null, …}

However, the next line where I call console.log(Object.keys(pos.coords)), I get an empty array:

[]

Likewise, if I try to use JSON.stringify(pos.coords), I just get an empty object {}.

Is there any reasonable way to loop through the keys of pos.coords? Must I make my own list of keys to loop through?

Brad
  • 159,648
  • 54
  • 349
  • 530
  • Try `Object.getOwnPropertyNames` (if they're not enumerable for some reason)? Or traverse the prototype chain to find getters. – Bergi Aug 22 '17 at 21:18
  • @Bergi `Object.getOwnPropertyNames(pos.coords)` also comes up as an empty array. – Brad Aug 22 '17 at 21:21
  • Seems there's an NPM package for this! https://github.com/zeke/geoposition-to-object With a hard-coded list of properties: https://github.com/zeke/geoposition-to-object/blob/master/index.js Strange. – Brad Aug 22 '17 at 21:23
  • Could be that they're "getter" functions defined on the prototype. `Object.getOwnPropertyNames(pos.coords.__proto__);` You can traverse them like this if so: `Object.getOwnPropertyNames(pos.coords.__proto__) .forEach(p => console.log(pos.coords[p]))` – spanky Aug 22 '17 at 21:28
  • @spanky That seems to be it. I suppose this is just an implementation quirk. I don't know what they'll throw in there in the future, so I think I'll just reduce a whitelist of properties for now. – Brad Aug 22 '17 at 21:33
  • 1
    @Brad Then try [this](https://stackoverflow.com/a/30158566/1048572), please. They must be somewhere… (OK, it's a host object that could work like a proxy, but I can't see any reason for that) – Bergi Aug 22 '17 at 21:34
  • @Bergi If you or spanky want to post an answer explaining this behavior, I'd be happy to mark it as an answer. Even better if you have a guess as to why they did it this way. :-) Thanks. – Brad Aug 22 '17 at 21:36
  • they are not "own" props, they are inherited. \ – dandavis Aug 22 '17 at 21:38
  • @Brad I suspect they're getters that access the internal native data representation. Btw, does `for … in` work? They might still be enumerable. – Bergi Aug 22 '17 at 21:38
  • @Bergi `for … in` does work. – Brad Aug 22 '17 at 21:46

1 Answers1

3

Object.keys(pos.coords) gets an empty array

Yes, the properties of the Coordinates interface are implemented as getters on the prototype object (instead of own properties), so Object.keys doesn't find them.

Is there any reasonable way to loop through the keys of pos.coords?

You can in fact just loop through them:

for (const p in pos.coords)
    console.log(p);

An alternative is to use

Object.getOwnPropertyNames(Object.getPrototypeOf(pos.coords));

Do you have a guess as to why they did it this way?

I suspect they're getters that access the internal native data representation linked from the host object. That way, they're implicitly readonly as the spec for the interface requires. They should have been able to achieve that by simply making them own, non-writable data properties either, though.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375