The short answer is that in your particular case, the choice of enter () parentNode is document (not body ).
Take a simple example to see what the enter () selection looks like. Assuming we have a document with a body without any p elements.
var ps = d3.select("body").selectAll("p") .data([0, 1, 2]);
Since there are no p elements, choosing enter () will have three elements. Let check input selection:

You see that the internal array has a property called parentNode. When you add new elements using selection.append () or selection.insert () new elements will be created as children of this parentNode.
So, when checking ps.enter()[0].parentNode , the body element will be shown. Now it becomes clear that when combining data, the choice before selectAll indicates parentNode; in the above case d3.select("body") .
What if we missed the select ("body") part in the data connection?
// example of bad data join var ps2 = d3.selectAll("p") .data([0, 1, 2]);
It turns out that in this case ps2.enter()[0].parentNode is #document ! This means that if you add elements using this enter () parameter, they will become child documents. The append method will add them to the end of the document; those. after the body.
The last case is basically what you come across. Your data is attached and entered incorrectly; he should follow this pattern:
d3.select(parent).selectAll(element) .data(data) .enter().append(element);
By the way, the HTML text element is missing. So append("text") does not seem significant.