Fair enough ;-)
So here is how I think about mutators. Others might think of it differently, and I welcome their input!
One key thing to keep in mind is that there are a bunch of places in the Blockly code where it needs to copy a block. That includes explicitly copy/pasting a block, dragging a block, connecting it to other blocks, or creating a new one from the toolbox. Blockly does that by looking at the type of the block, running the init method for that block type, and copying over the standard attributes of the block (e.g. its field's values). Unfortunately, that's not quite enough. Why? Because blocks sometimes morph (i.e. mutate) in non-standard ways (e.g. adding or removing inputs) based on user or programmatic actions. So, copying those mutated blocks requires more information than just their type. That extra information is encoded in the "extra" state that is written and read by the saveExtraState and loadExtraState methods of blocks.
The saveExtraState method allows you (the block definition writer) to encode whatever extra information you need to later recreate those mutations (i.e. changes) in your loadExtraState method in order to make a copied block match its source block. Note that the saveExtraState and loadExtraState methods create and read the block's extra state as "Plain Old JavaScript Objects" (aka POJOs). That is, objects that are not instances of classes.
There is another major case where mutators (and their saveExtraState and loadExtraState methods) come into play and that's in the saving and loading of workspaces (or other sets of blocks), which is a common feature of many uses of Blockly. Blockly does that through a process commonly called serialization. During serialization, Blockly creates a state object for each block which contains the block's type, the values of its standard attributes and its extra state. This larger block state object is also a POJO, which means that it can then be easily converted to a textual JSON string which can be externally saved. The process of generating the JSON string which represents the workspace (or set of blocks) is serialization. Deserialization is just the reverse process of taking the JSON string and populating a workspace from it.
The call to Blockly.Extensions.registerMutator, takes a name for the mutator and what it calls a mixin object, which is an object which contains the extra state fields and your saveExtraState and loadExtraState field whose values are the functions mentioned above. You specify the name of the mutator in your block type definition.
Note that there are other, optional, arguments to Blockly.Extensions.registerMutator, but I'm trying to keep things as simple as I can ;-).
One potentially confusing thing is that Blockly sometimes (in its code and documentation) calls the process of creating the state POJO "serialization" and it sometimes refers to the type of the state object as "JSON". Strictly speaking, the term "serialization" usually means the process of creating the external representation of an object (i.e. the JSON string), not the state object. Also, strictly speaking" the type of the state object is just a JavaScript object (or POJO), i.e. not JSON. JSON, properly speaking, is a textual format.
I hope that this helps clarify mutators and does not further confuse you!
-Mark