D3 .merge function

You actually have two issues here:

  1. Understanding the merge() method;
  2. Understanding that piece of code you shared;

Regarding #1 you already received an answer. Regarding #2, these are my two cents: that code does not make sense.

This is simple to understand: the ticked function runs dozens of times per second. Why would you re-bind the data and reassign the update, enter and exit selections dozens of times per second, if the data doesn't change? (it's worth mentioning that the author of that code is a good programmer, something strange has happened here... after all, we all make mistakes)

The ticked function just need to compute the positions of the elements, that's all.

Here is that same code you linked with the ticked function simplified to just this:

function ticked() {
    u.attr('cx', function(d) {
            return d.x;
        })
        .attr('cy', function(d) {
            return d.y;
        })
}

And here the running code:

var width = 600,
  height = 400;

var colorScale = ['orange', 'lightblue', '#B19CD9'];
var xCenter = [100, 300, 500]

var numNodes = 100;
var nodes = d3.range(numNodes).map(function(d, i) {
  return {
    radius: Math.random() * 25,
    category: i % 3
  }
});

var u = d3.select('svg g')
  .selectAll('circle')
  .data(nodes);

var enter = u.enter()
  .append('circle')
  .attr('r', function(d) {
    return d.radius;
  })
  .style('fill', function(d) {
    return colorScale[d.category];
  });

u = enter.merge(u);

u.exit().remove();

var simulation = d3.forceSimulation(nodes)
  .force('charge', d3.forceManyBody().strength(5))
  .force('x', d3.forceX().x(function(d) {
    return xCenter[d.category];
  }))
  .force('collision', d3.forceCollide().radius(function(d) {
    return d.radius;
  }))
  .on('tick', ticked);

function ticked() {
  u.attr('cx', function(d) {
      return d.x;
    })
    .attr('cy', function(d) {
      return d.y;
    })
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="content">
  <svg width="700" height="400">
    <g transform="translate(50, 200)"></g>
  </svg>
</div>

The documentation explains very well what that function does, so what it does is instead of you having to do this

u.attr("cx", d => d.x)
 .attr("cy", d => d.y);

u.enter().append("circle").attr("r",5)
        .attr("cx", d => d.x)
        .attr("cy", d => d.y);

You can just call attr once like

u.enter().append("circle").attr("r",5)
        .merge(u) // after this point, any updates will apply to both u and u.enter() selections
        .attr("cx", d => d.x)
        .attr("cy", d => d.y)

It will set attributes cx and cy on both u-the update selection and u.enter()-the enter selection

Why is it necessary to remove excess objects w/ the exit selection?

Because the exit selection contains any extra DOM elements that were not bound to the elements in the array you passed to data(), you can do whatever you need on the exit colllection, for example setting the styles by calling u.exit().style(...), etc. instead of calling remove to delete them from the DOM


In view of the comments I should alert readers that this answer may be wrong. So please read the comments first

TL;DR - merge makes two node collections into one

var x = d3.selectAll(".node");
var y = d3.selectAll(".link");
var z = x.merge(y);

z now contains all the elements in x AND all the elements in y.