sq_peg_rnd_hole
sq_peg_rnd_hole

Reputation: 73

d3.keys() syntax clarification?

Hi very new to learning JavaScript and d3.js

The following syntax creates a new array of the property names from each object held in an associative array called "data".

The property name for the first object in "data" is excluded.

d3.keys(data[0])
  .filter(function(key) { return key !== "date";}))

I'm not getting why the code below doesn't give me the same result?

d3.keys(data)
  .filter(function(key) { return key !== "date";}))

Why tell d3 to select the [0] index position as well as to filter on an object property name. Doesn't the d3.keys(object) method run through the associative array and return a new array containing the property names of each of the specified objects by definition? It makes me think you just need to filter?

Upvotes: 1

Views: 3658

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102188

The explanation is simple: you cannot pass an array to d3.keys, it has to be an object instead. The API is clear about that:

Returns an array containing the property names of the specified object. (emphasis mine)

If you look at the source code, you'll see that d3.keys uses a for...in loop:

export default function(map) {
    var keys = [];
    for (var key in map) keys.push(key);
    return keys;
};

This won't work with an array. Let's see:

function d3keys(map) {
  var keys = [];
  for (var key in map) keys.push(key);
  return keys;
}

var myArray = [{
  x: "foo",
  y: "bar"
}, {
  x: "foobar",
  y: "barbaz"
}];

console.log(d3keys(myArray))

The same thing happens if you use Object.keys(), without D3:

var myArray = [{
  x: "foo",
  y: "bar"
}, {
  x: "foobar",
  y: "barbaz"
}];

console.log(Object.keys(myArray))

And the explanation is that you cannot (or should not) use for...in with an array. According to MDN:

Note: for...in should not be used to iterate over an Array where the index order is important.

And the most important part:

Array indexes are just enumerable properties with integer names. (emphasis mine)

So, we have to pass an object instead. In this case, myArray[0] for instance:

function d3keys(map) {
  var keys = [];
  for (var key in map) keys.push(key);
  return keys;
}

var myArray = [{
  x: "foo",
  y: "bar"
}, {
  x: "foobar",
  y: "barbaz"
}];

console.log(d3keys(myArray[0]))

Upvotes: 2

Related Questions